org.yamcs.mdb.XtceAssembler Maven / Gradle / Ivy
package org.yamcs.mdb;
import static org.yamcs.xtce.xml.Constants.ATTR_ENCODING;
import static org.yamcs.xtce.xml.Constants.ATTR_INITIAL_VALUE;
import static org.yamcs.xtce.xml.Constants.ATTR_PARAMETER_REF;
import static org.yamcs.xtce.xml.Constants.ATTR_SIZE_IN_BITS;
import static org.yamcs.xtce.xml.Constants.ELEM_COMPARISON_OPERATOR;
import static org.yamcs.xtce.xml.Constants.ELEM_CONDITION;
import static org.yamcs.xtce.xml.Constants.ELEM_ENCODING;
import static org.yamcs.xtce.xml.Constants.ELEM_FLOAT_DATA_ENCODING;
import static org.yamcs.xtce.xml.Constants.ELEM_PARAMETER_INSTANCE_REF;
import static org.yamcs.xtce.xml.Constants.ELEM_PARAMETER_REF;
import static org.yamcs.xtce.xml.Constants.ELEM_PARAMETER_VALUE_CHANGE;
import static org.yamcs.xtce.xml.Constants.ELEM_SIZE_IN_BITS;
import static org.yamcs.xtce.xml.Constants.ELEM_VALUE;
import static org.yamcs.xtce.xml.Constants.ELEM_VARIABLE;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
import java.util.function.Predicate;
import javax.xml.XMLConstants;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.yamcs.logging.Log;
import org.yamcs.utils.StringConverter;
import org.yamcs.xtce.ANDedConditions;
import org.yamcs.xtce.AbsoluteTimeArgumentType;
import org.yamcs.xtce.AbsoluteTimeParameterType;
import org.yamcs.xtce.AggregateArgumentType;
import org.yamcs.xtce.AggregateDataType;
import org.yamcs.xtce.AggregateParameterType;
import org.yamcs.xtce.AlarmRanges;
import org.yamcs.xtce.Algorithm;
import org.yamcs.xtce.AncillaryData;
import org.yamcs.xtce.Argument;
import org.yamcs.xtce.ArgumentAssignment;
import org.yamcs.xtce.ArgumentEntry;
import org.yamcs.xtce.ArgumentInstanceRef;
import org.yamcs.xtce.ArgumentType;
import org.yamcs.xtce.ArrayParameterEntry;
import org.yamcs.xtce.ArrayParameterType;
import org.yamcs.xtce.BinaryArgumentType;
import org.yamcs.xtce.BinaryDataEncoding;
import org.yamcs.xtce.BinaryParameterType;
import org.yamcs.xtce.BooleanArgumentType;
import org.yamcs.xtce.BooleanExpression;
import org.yamcs.xtce.BooleanParameterType;
import org.yamcs.xtce.Calibrator;
import org.yamcs.xtce.CheckWindow;
import org.yamcs.xtce.CheckWindow.TimeWindowIsRelativeToType;
import org.yamcs.xtce.CommandContainer;
import org.yamcs.xtce.CommandVerifier;
import org.yamcs.xtce.Comparison;
import org.yamcs.xtce.ComparisonList;
import org.yamcs.xtce.Condition;
import org.yamcs.xtce.ContainerEntry;
import org.yamcs.xtce.ContextCalibrator;
import org.yamcs.xtce.CustomAlgorithm;
import org.yamcs.xtce.DataEncoding;
import org.yamcs.xtce.DataSource;
import org.yamcs.xtce.DataType;
import org.yamcs.xtce.DynamicIntegerValue;
import org.yamcs.xtce.EnumeratedArgumentType;
import org.yamcs.xtce.EnumeratedDataType;
import org.yamcs.xtce.EnumeratedParameterType;
import org.yamcs.xtce.EnumerationAlarm.EnumerationAlarmItem;
import org.yamcs.xtce.EnumerationContextAlarm;
import org.yamcs.xtce.FixedIntegerValue;
import org.yamcs.xtce.FixedValueEntry;
import org.yamcs.xtce.FloatArgumentType;
import org.yamcs.xtce.FloatDataEncoding;
import org.yamcs.xtce.FloatParameterType;
import org.yamcs.xtce.FloatValidRange;
import org.yamcs.xtce.Header;
import org.yamcs.xtce.History;
import org.yamcs.xtce.InputParameter;
import org.yamcs.xtce.IntegerArgumentType;
import org.yamcs.xtce.IntegerDataEncoding;
import org.yamcs.xtce.IntegerParameterType;
import org.yamcs.xtce.IntegerValidRange;
import org.yamcs.xtce.IntegerValue;
import org.yamcs.xtce.MatchCriteria;
import org.yamcs.xtce.MathAlgorithm;
import org.yamcs.xtce.MathOperation;
import org.yamcs.xtce.MathOperation.ElementType;
import org.yamcs.xtce.MathOperationCalibrator;
import org.yamcs.xtce.Member;
import org.yamcs.xtce.MetaCommand;
import org.yamcs.xtce.NameDescription;
import org.yamcs.xtce.NumericAlarm;
import org.yamcs.xtce.NumericContextAlarm;
import org.yamcs.xtce.NumericDataEncoding;
import org.yamcs.xtce.ORedConditions;
import org.yamcs.xtce.OnParameterUpdateTrigger;
import org.yamcs.xtce.OnPeriodicRateTrigger;
import org.yamcs.xtce.OperatorType;
import org.yamcs.xtce.OutputParameter;
import org.yamcs.xtce.Parameter;
import org.yamcs.xtce.ParameterEntry;
import org.yamcs.xtce.ParameterInstanceRef;
import org.yamcs.xtce.ParameterOrArgumentRef;
import org.yamcs.xtce.ParameterType;
import org.yamcs.xtce.ParameterValueChange;
import org.yamcs.xtce.PathElement;
import org.yamcs.xtce.PolynomialCalibrator;
import org.yamcs.xtce.ReferenceTime;
import org.yamcs.xtce.Repeat;
import org.yamcs.xtce.SequenceContainer;
import org.yamcs.xtce.SequenceEntry;
import org.yamcs.xtce.SequenceEntry.ReferenceLocationType;
import org.yamcs.xtce.Significance;
import org.yamcs.xtce.SpaceSystem;
import org.yamcs.xtce.SplineCalibrator;
import org.yamcs.xtce.SplinePoint;
import org.yamcs.xtce.StringArgumentType;
import org.yamcs.xtce.StringDataEncoding;
import org.yamcs.xtce.StringDataEncoding.SizeType;
import org.yamcs.xtce.StringParameterType;
import org.yamcs.xtce.TimeEpoch;
import org.yamcs.xtce.TransmissionConstraint;
import org.yamcs.xtce.TriggerSetType;
import org.yamcs.xtce.UnitType;
import org.yamcs.xtce.ValueEnumeration;
import org.yamcs.xtce.ValueEnumerationRange;
import org.yamcs.xtce.util.DoubleRange;
import org.yamcs.xtce.xml.XtceStaxReader;
/**
*
* Experimental export of Mission Database to XTCE.
*
*
* @author nm
*
*/
public class XtceAssembler {
private static final String NS_XTCE_V1_2 = "http://www.omg.org/spec/XTCE/20180204";
private static final Log log = new Log(XtceAssembler.class);
private static final List XTCE_VERIFIER_STAGES = Arrays.asList(
"TransferredToRange", "SentFromRange", "Received", "Accepted", "Queued", "Execution", "Complete", "Failed");
boolean emitYamcsNamespace = false;
private SpaceSystem currentSpaceSystem;
final DatatypeFactory dataTypeFactory;
Mdb mdb;
public XtceAssembler() {
try {
dataTypeFactory = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException e) {
throw new RuntimeException(e);
}
}
public final String toXtce(Mdb mdb) {
return toXtce(mdb, "/", fqn -> true);
}
/**
* Convert the mission database to XTCE starting at the specified top container and saving only filtered containers.
*
* The filter will be called with the Fully Qualified Name of each container under the top and if it returns true,
* the specified container will be saved.
*
* Note that in the resulting file (if the top is not the root) the containers will have their qualified name
* stripped by the top name. In addition there might be references to objects from SpaceSystems that are not part of
* the export.
*
*
* @param mdb
* @param topSpaceSystem
* the fully qualified name of the space system where the export should start from. If the space system
* does not exist, a {@link IllegalArgumentException} will be thrown.
* @param filter
* @return
*/
public final String toXtce(Mdb mdb, String topSpaceSystem, Predicate filter) {
this.mdb = mdb;
try {
String unindentedXML;
try (Writer writer = new StringWriter()) {
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter xmlWriter = factory.createXMLStreamWriter(writer);
xmlWriter.writeStartDocument();
SpaceSystem top = mdb.getSpaceSystem(topSpaceSystem);
if (top == null) {
throw new IllegalArgumentException("Unknown space system '" + topSpaceSystem + "'");
}
writeSpaceSystem(xmlWriter, top, true, filter);
xmlWriter.writeEndDocument();
xmlWriter.close();
unindentedXML = writer.toString();
}
try (Reader reader = new StringReader(unindentedXML); Writer writer = new StringWriter()) {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
// Sonarqube suggestion to protect Java XML Parsers from XXE attack
// see https://rules.sonarsource.com/java/RSPEC-2755
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
// Without this seemingly unnecessary property, the Java XML implementation
// will put the XML declaration and the root tag on the same line (missing newline).
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "no");
StreamSource source = new StreamSource(reader);
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
return writer.toString();
}
} catch (IOException | XMLStreamException | TransformerException e) {
throw new Error(e);
}
}
private void writeSpaceSystem(XMLStreamWriter doc, SpaceSystem spaceSystem, boolean emitNamespace,
Predicate filter)
throws XMLStreamException {
if (!filter.test(spaceSystem.getQualifiedName())) {
log.debug("Skipping {}", spaceSystem.getQualifiedName());
return;
}
this.currentSpaceSystem = spaceSystem;
doc.writeStartElement("SpaceSystem");
if (emitNamespace) {
doc.writeDefaultNamespace(NS_XTCE_V1_2);
}
writeNameDescription(doc, spaceSystem);
Header header = spaceSystem.getHeader();
if (header != null) {
writeHeader(doc, header);
}
doc.writeStartElement("TelemetryMetaData");
if (!spaceSystem.getParameterTypes().isEmpty()) {
doc.writeStartElement("ParameterTypeSet");
for (ParameterType ptype : spaceSystem.getParameterTypes()) {
writeParameterType(doc, ptype);
}
doc.writeEndElement();
}
if (!spaceSystem.getParameters().isEmpty()) {
doc.writeStartElement("ParameterSet");
for (Parameter parameter : spaceSystem.getParameters()) {
if (parameter.getParameterType() == null) {
continue;
}
writeParameter(doc, parameter);
}
doc.writeEndElement();
}
if (!spaceSystem.getSequenceContainers().isEmpty()) {
doc.writeStartElement("ContainerSet");
for (SequenceContainer seq : spaceSystem.getSequenceContainers()) {
writeSequenceContainer(doc, seq);
}
doc.writeEndElement();
}
if (!spaceSystem.getAlgorithms().isEmpty()) {
doc.writeStartElement("AlgorithmSet");
for (Algorithm algo : spaceSystem.getAlgorithms()) {
if (algo instanceof MathAlgorithm) {
writeMathAlgorithm(doc, (MathAlgorithm) algo);
} else {
writeCustomAlgorithm(doc, (CustomAlgorithm) algo, "CustomAlgorithm", false);
}
}
doc.writeEndElement();
}
doc.writeEndElement();// TelemetryMetaData
if (!spaceSystem.getMetaCommands().isEmpty()) {
doc.writeStartElement("CommandMetaData");
if (!spaceSystem.getArgumentTypes().isEmpty()) {
doc.writeStartElement("ArgumentTypeSet");
for (ArgumentType atype : spaceSystem.getArgumentTypes()) {
writeArgumentType(doc, atype);
}
doc.writeEndElement();
}
doc.writeStartElement("MetaCommandSet");
for (MetaCommand command : spaceSystem.getMetaCommands()) {
writeMetaCommand(doc, command);
}
doc.writeEndElement();// MetaCommandSet
doc.writeEndElement();// CommandMetaData
}
for (SpaceSystem sub : spaceSystem.getSubSystems()) {
if (!emitYamcsNamespace && Mdb.YAMCS_SPACESYSTEM_NAME.equals(sub.getQualifiedName())) {
continue;
}
writeSpaceSystem(doc, sub, false, filter);
}
doc.writeEndElement();
}
private static void writeHeader(XMLStreamWriter doc, Header header) throws XMLStreamException {
doc.writeStartElement("Header");
doc.writeAttribute("validationStatus", "Unknown"); // Required attribute
if (header.getVersion() != null) {
doc.writeAttribute("version", header.getVersion());
}
if (header.getDate() != null) {
doc.writeAttribute("date", header.getDate());
}
if (!header.getHistoryList().isEmpty()) {
doc.writeStartElement("HistorySet");
for (History history : header.getHistoryList()) {
doc.writeStartElement("History");
if (history.getDate() != null && !history.getDate().isEmpty()) {
doc.writeCharacters(history.getDate());
doc.writeCharacters(": ");
}
doc.writeCharacters(history.getMessage());
doc.writeEndElement();
}
doc.writeEndElement();
}
doc.writeEndElement();
}
private void writeParameter(XMLStreamWriter doc, Parameter parameter) throws XMLStreamException {
doc.writeStartElement("Parameter");
ParameterType ptype = parameter.getParameterType();
writeNameReferenceAttribute(doc, "parameterTypeRef", (NameDescription) ptype); // Required attribute
if (parameter.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, parameter.getInitialValue().toString());
}
writeNameDescription(doc, parameter);
if (hasNonDefaultProperties(parameter)) {
doc.writeStartElement("ParameterProperties");
if (parameter.getDataSource() != DataSource.TELEMETERED) {
doc.writeAttribute("dataSource", parameter.getDataSource().name().toLowerCase());
}
if (!parameter.isPersistent()) {
doc.writeAttribute("persistence", "false");
}
doc.writeEndElement();// ParameterProperties
}
doc.writeEndElement();// Parameter
}
boolean hasNonDefaultProperties(Parameter p) {
return p.getDataSource() != DataSource.TELEMETERED || !p.isPersistent();
}
private void writeParameterType(XMLStreamWriter doc, ParameterType ptype) throws XMLStreamException {
if (ptype instanceof StringParameterType) {
writeStringParameterType(doc, (StringParameterType) ptype);
} else if (ptype instanceof IntegerParameterType) {
writeIntegerParameterType(doc, (IntegerParameterType) ptype);
} else if (ptype instanceof AggregateParameterType) {
writeAggregateParameterType(doc, (AggregateParameterType) ptype);
} else if (ptype instanceof FloatParameterType) {
writeFloatParameterType(doc, (FloatParameterType) ptype);
} else if (ptype instanceof BooleanParameterType) {
writeBooleanParameterType(doc, (BooleanParameterType) ptype);
} else if (ptype instanceof EnumeratedParameterType) {
writeEnumeratedParameterType(doc, (EnumeratedParameterType) ptype);
} else if (ptype instanceof AbsoluteTimeParameterType) {
writeAbsoluteTimeParameterType(doc, (AbsoluteTimeParameterType) ptype);
} else if (ptype instanceof ArrayParameterType) {
writeArrayParameterType(doc, (ArrayParameterType) ptype);
} else if (ptype instanceof BinaryParameterType) {
writeBinaryParameterType(doc, (BinaryParameterType) ptype);
} else {
log.warn("Unexpected parameter type " + ptype.getClass());
}
}
private void writeEnumeratedParameterType(XMLStreamWriter doc, EnumeratedParameterType ptype)
throws XMLStreamException {
doc.writeStartElement("EnumeratedParameterType");
writeEnumeratedDataType(doc, ptype);
if (ptype.getDefaultAlarm() != null) {
doc.writeStartElement("DefaultAlarm");
writeEnumerationAlarm(doc, ptype.getDefaultAlarm().getAlarmList());
doc.writeEndElement();// DefaultAlarm
}
if (ptype.getContextAlarmList() != null) {
doc.writeStartElement("ContextAlarmList");
for (EnumerationContextAlarm eca : ptype.getContextAlarmList()) {
doc.writeStartElement("ContextAlarm");
writeEnumerationAlarm(doc, eca.getAlarmList());
doc.writeStartElement("ContextMatch");
writeMatchCriteria(doc, eca.getContextMatch());
doc.writeEndElement();// ContextMatch
doc.writeEndElement();// ContextAlarm
}
doc.writeEndElement();// ContextAlarmList
}
doc.writeEndElement();
}
private static void writeAggregateParameterType(XMLStreamWriter doc, AggregateParameterType ptype)
throws XMLStreamException {
doc.writeStartElement("AggregateParameterType");
writeAggregateDataType(doc, ptype);
doc.writeEndElement();
}
private static void writeAggregateDataType(XMLStreamWriter doc, AggregateDataType type) throws XMLStreamException {
writeNameDescription(doc, type);
doc.writeStartElement("MemberList");
for (Member member : type.getMemberList()) {
DataType mtype = member.getType();
doc.writeStartElement("Member");
writeNameDescription(doc, member);
doc.writeAttribute("typeRef", mtype.getName());
if (member.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, member.getInitialValue().toString());
}
doc.writeEndElement();
}
doc.writeEndElement();
}
private void writeIntegerParameterType(XMLStreamWriter doc, IntegerParameterType ptype)
throws XMLStreamException {
doc.writeStartElement("IntegerParameterType");
if (ptype.getSizeInBits() != 32) {
doc.writeAttribute(ATTR_SIZE_IN_BITS, Integer.toString(ptype.getSizeInBits()));
}
if (!ptype.isSigned()) {
doc.writeAttribute("signed", "false");
}
if (ptype.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, ptype.getInitialValue().toString());
}
writeNameDescription(doc, ptype);
if (ptype.getValidRange() != null) {
IntegerValidRange range = ptype.getValidRange();
doc.writeStartElement("ValidRange");
doc.writeAttribute("minInclusive", String.valueOf(range.getMinInclusive()));
doc.writeAttribute("maxInclusive", String.valueOf(range.getMaxInclusive()));
if (!range.isValidRangeAppliesToCalibrated()) {
doc.writeAttribute("validRangeAppliesToCalibrated", "false");
}
doc.writeEndElement();
}
writeUnitSet(doc, ptype.getUnitSet());
if (ptype.getEncoding() != null) {
writeDataEncoding(doc, ptype.getEncoding());
}
doc.writeEndElement();
}
private void writeFloatParameterType(XMLStreamWriter doc, FloatParameterType ptype)
throws XMLStreamException {
doc.writeStartElement("FloatParameterType");
doc.writeAttribute(ATTR_SIZE_IN_BITS, Integer.toString(ptype.getSizeInBits()));
if (ptype.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, ptype.getInitialValue().toString());
}
writeNameDescription(doc, ptype);
if (ptype.getValidRange() != null) {
FloatValidRange range = ptype.getValidRange();
writeRange(doc, "ValidRange", range, range.isValidRangeAppliesToCalibrated() ? null : Boolean.FALSE);
}
writeUnitSet(doc, ptype.getUnitSet());
if (ptype.getEncoding() != null) {
writeDataEncoding(doc, ptype.getEncoding());
}
NumericAlarm alarm = ptype.getDefaultAlarm();
if (alarm != null) {
doc.writeStartElement("DefaultAlarm");
if (alarm.getMinViolations() != 1) {
doc.writeAttribute("minViolations", Integer.toString(alarm.getMinViolations()));
}
writeNumericAlarm(doc, alarm);
doc.writeEndElement();
}
if (ptype.getContextAlarmList() != null) {
doc.writeStartElement("ContextAlarmList");
for (NumericContextAlarm nca : ptype.getContextAlarmList()) {
doc.writeStartElement("ContextAlarm");
writeNumericAlarm(doc, nca);
doc.writeStartElement("ContextMatch");
writeMatchCriteria(doc, nca.getContextMatch());
doc.writeEndElement();// ContextMatch
doc.writeEndElement();// ContextAlarm
}
doc.writeEndElement();// ContextAlarmList
}
doc.writeEndElement();// FloatParameterType
}
private static void writeRange(XMLStreamWriter doc, String elementName, DoubleRange range)
throws XMLStreamException {
writeRange(doc, elementName, range, null);
}
private static void writeRange(XMLStreamWriter doc, String elementName, DoubleRange range,
Boolean appliesToCalibrated)
throws XMLStreamException {
if (range == null) {
return;
}
doc.writeStartElement(elementName);
if (range.isMinInclusive()) {
doc.writeAttribute("minInclusive", String.valueOf(range.getMin()));
} else {
doc.writeAttribute("minExclusive", String.valueOf(range.getMin()));
}
if (range.isMaxInclusive()) {
doc.writeAttribute("maxInclusive", String.valueOf(range.getMax()));
} else {
doc.writeAttribute("maxExclusive", String.valueOf(range.getMax()));
}
if (appliesToCalibrated != null) {
doc.writeAttribute("validRangeAppliesToCalibrated", appliesToCalibrated.toString());
}
doc.writeEndElement();
}
private static void writeNumericAlarm(XMLStreamWriter doc, NumericAlarm na) throws XMLStreamException {
doc.writeStartElement("StaticAlarmRanges");
AlarmRanges ar = na.getStaticAlarmRanges();
writeRange(doc, "WatchRange", ar.getWatchRange());
writeRange(doc, "WarningRange", ar.getWarningRange());
writeRange(doc, "DistressRange", ar.getDistressRange());
writeRange(doc, "CriticalRange", ar.getCriticalRange());
writeRange(doc, "SevereRange", ar.getSevereRange());
doc.writeEndElement();
}
private static void writeEnumerationAlarm(XMLStreamWriter doc, List list)
throws XMLStreamException {
doc.writeStartElement("EnumerationAlarmList");
for (EnumerationAlarmItem eai : list) {
doc.writeStartElement("EnumerationAlarm");
doc.writeAttribute("enumerationLabel", eai.getEnumerationLabel());
doc.writeAttribute("alarmLevel", eai.getAlarmLevel().xtceName);
doc.writeEndElement();// EnumerationAlarm
}
doc.writeEndElement();// EnumerationAlarmList
}
private void writeBooleanParameterType(XMLStreamWriter doc, BooleanParameterType ptype)
throws XMLStreamException {
doc.writeStartElement("BooleanParameterType");
if (ptype.getInitialValue() != null) {
if (ptype.getInitialValue()) {
doc.writeAttribute(ATTR_INITIAL_VALUE, ptype.getOneStringValue());
} else {
doc.writeAttribute(ATTR_INITIAL_VALUE, ptype.getZeroStringValue());
}
}
doc.writeAttribute("oneStringValue", ptype.getOneStringValue());
doc.writeAttribute("zeroStringValue", ptype.getZeroStringValue());
writeNameDescription(doc, ptype);
writeUnitSet(doc, ptype.getUnitSet());
if (ptype.getEncoding() != null) {
writeDataEncoding(doc, ptype.getEncoding());
}
doc.writeEndElement();
}
private void writeAbsoluteTimeParameterType(XMLStreamWriter doc, AbsoluteTimeParameterType ptype)
throws XMLStreamException {
doc.writeStartElement("AbsoluteTimeParameterType");
if (ptype.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, ptype.getInitialValue().toString());
}
writeNameDescription(doc, ptype);
doc.writeStartElement(ELEM_ENCODING);
if (ptype.getScale() != 1) {
doc.writeAttribute("scale", Double.toString(ptype.getScale()));
}
if (ptype.getOffset() != 0) {
doc.writeAttribute("offset", Double.toString(ptype.getOffset()));
}
if (ptype.getEncoding() != null) {
writeDataEncoding(doc, ptype.getEncoding());
}
doc.writeEndElement();
ReferenceTime referenceTime = ptype.getReferenceTime();
if (referenceTime != null) {
writeReferenceTime(doc, referenceTime);
}
doc.writeEndElement();
}
private void writeReferenceTime(XMLStreamWriter doc, ReferenceTime referenceTime) throws XMLStreamException {
doc.writeStartElement("ReferenceTime");
if (referenceTime.getOffsetFrom() != null) {
writeParameterInstanceRef(doc, "OffsetFrom", referenceTime.getOffsetFrom());
} else if (referenceTime.getEpoch() != null) {
doc.writeStartElement("Epoch");
TimeEpoch te = referenceTime.getEpoch();
if (te.getCommonEpoch() != null) {
doc.writeCharacters(te.getCommonEpoch().name());
} else {
doc.writeCharacters(te.getDateTime());
}
doc.writeEndElement();
}
doc.writeEndElement();
}
private void writeArrayParameterType(XMLStreamWriter doc, ArrayParameterType ptype)
throws XMLStreamException {
doc.writeStartElement("ArrayParameterType");
writeNameReferenceAttribute(doc, "arrayTypeRef", (NameDescription) ptype.getElementType());
if (ptype.getSize() == null) {
doc.writeAttribute("numberOfDimensions", Integer.toString(ptype.getNumberOfDimensions()));
}
writeNameDescription(doc, ptype);
if (ptype.getSize() != null) {
writeDimensionList(doc, ptype.getSize());
}
doc.writeEndElement();
}
private void writeBinaryParameterType(XMLStreamWriter doc, BinaryParameterType ptype)
throws XMLStreamException {
doc.writeStartElement("BinaryParameterType");
if (ptype.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, ptype.getInitialValue().toString());
}
writeNameDescription(doc, ptype);
if (ptype.getEncoding() != null) {
writeDataEncoding(doc, ptype.getEncoding());
}
doc.writeEndElement();
}
private void writeArgumentType(XMLStreamWriter doc, ArgumentType atype) throws XMLStreamException {
if (atype instanceof StringArgumentType) {
writeStringArgumentType(doc, (StringArgumentType) atype);
} else if (atype instanceof IntegerArgumentType) {
writeIntegerArgumentType(doc, (IntegerArgumentType) atype);
} else if (atype instanceof FloatArgumentType) {
writeFloatArgumentType(doc, (FloatArgumentType) atype);
} else if (atype instanceof BooleanArgumentType) {
writeBooleanArgumentType(doc, (BooleanArgumentType) atype);
} else if (atype instanceof EnumeratedArgumentType) {
writeEnumeratedArgumentType(doc, (EnumeratedArgumentType) atype);
} else if (atype instanceof AggregateArgumentType) {
writeAggregateArgumentType(doc, (AggregateArgumentType) atype);
} else if (atype instanceof BinaryArgumentType) {
writeBinaryArgumentType(doc, (BinaryArgumentType) atype);
} else if (atype instanceof AbsoluteTimeArgumentType) {
writeAbsoluteTimeArgumentType(doc, (AbsoluteTimeArgumentType) atype);
} else {
log.warn("Unexpected argument type " + atype.getClass());
}
}
private void writeStringArgumentType(XMLStreamWriter doc, StringArgumentType atype)
throws XMLStreamException {
doc.writeStartElement("StringArgumentType");
writeNameDescription(doc, atype);
writeUnitSet(doc, atype.getUnitSet());
if (atype.getEncoding() != null) {
writeDataEncoding(doc, atype.getEncoding());
}
doc.writeEndElement();
}
private void writeEnumeratedArgumentType(XMLStreamWriter doc, EnumeratedArgumentType atype)
throws XMLStreamException {
doc.writeStartElement("EnumeratedArgumentType");
writeEnumeratedDataType(doc, atype);
doc.writeEndElement();
}
private void writeEnumeratedDataType(XMLStreamWriter doc, EnumeratedDataType type) throws XMLStreamException {
if (type.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, type.getInitialValue());
}
writeNameDescription(doc, type);
writeUnitSet(doc, type.getUnitSet());
if (type.getEncoding() != null) {
writeDataEncoding(doc, type.getEncoding());
}
doc.writeStartElement("EnumerationList");
for (ValueEnumeration valueEnumeration : type.getValueEnumerationList()) {
doc.writeStartElement("Enumeration");
doc.writeAttribute("label", valueEnumeration.getLabel());
doc.writeAttribute("value", Long.toString(valueEnumeration.getValue()));
String description = valueEnumeration.getDescription();
if (description != null) {
doc.writeAttribute("shortDescription", description);
}
doc.writeEndElement();
}
for (ValueEnumerationRange ver : type.getValueEnumerationRangeList()) {
doc.writeStartElement("Enumeration");
doc.writeAttribute("label", ver.getLabel());
doc.writeAttribute("value", Long.toString((long) ver.getMin()));
doc.writeAttribute("maxValue", Long.toString((long) ver.getMax()));
doc.writeEndElement();
}
doc.writeEndElement(); // EnumerationList
}
private void writeIntegerArgumentType(XMLStreamWriter doc, IntegerArgumentType atype)
throws XMLStreamException {
doc.writeStartElement("IntegerArgumentType");
doc.writeAttribute(ATTR_SIZE_IN_BITS, Integer.toString(atype.getSizeInBits()));
doc.writeAttribute("signed", atype.isSigned() ? "true" : "false");
if (atype.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, atype.getInitialValue().toString());
}
writeNameDescription(doc, atype);
writeUnitSet(doc, atype.getUnitSet());
if (atype.getEncoding() != null) {
writeDataEncoding(doc, atype.getEncoding());
}
if (atype.getValidRange() != null) {
doc.writeStartElement("ValidRangeSet");
IntegerValidRange range = atype.getValidRange();
if (!range.isValidRangeAppliesToCalibrated()) {
doc.writeAttribute("validRangeAppliesToCalibrated", "false");
}
doc.writeStartElement("ValidRange");
doc.writeAttribute("minInclusive", String.valueOf(range.getMinInclusive()));
doc.writeAttribute("maxInclusive", String.valueOf(range.getMaxInclusive()));
doc.writeEndElement(); // ValidRange
doc.writeEndElement(); // ValidRangeSet
}
doc.writeEndElement();
}
private void writeFloatArgumentType(XMLStreamWriter doc, FloatArgumentType atype)
throws XMLStreamException {
doc.writeStartElement("FloatArgumentType");
doc.writeAttribute(ATTR_SIZE_IN_BITS, Integer.toString(atype.getSizeInBits()));
if (atype.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, atype.getInitialValue().toString());
}
writeNameDescription(doc, atype);
if (atype.getValidRange() != null) {
FloatValidRange range = atype.getValidRange();
doc.writeStartElement("ValidRange");
if (range.isMinInclusive()) {
doc.writeAttribute("minInclusive", String.valueOf(range.getMin()));
} else {
doc.writeAttribute("minExclusive", String.valueOf(range.getMin()));
}
if (range.isMaxInclusive()) {
doc.writeAttribute("maxInclusive", String.valueOf(range.getMax()));
} else {
doc.writeAttribute("maxExclusive", String.valueOf(range.getMax()));
}
doc.writeAttribute("validRangeAppliesToCalibrated", "true");
doc.writeEndElement();
}
writeUnitSet(doc, atype.getUnitSet());
if (atype.getEncoding() != null) {
writeDataEncoding(doc, atype.getEncoding());
}
doc.writeEndElement();
}
private void writeBooleanArgumentType(XMLStreamWriter doc, BooleanArgumentType atype)
throws XMLStreamException {
doc.writeStartElement("BooleanArgumentType");
if (atype.getInitialValue() != null) {
if (atype.getInitialValue()) {
doc.writeAttribute(ATTR_INITIAL_VALUE, atype.getOneStringValue());
} else {
doc.writeAttribute(ATTR_INITIAL_VALUE, atype.getZeroStringValue());
}
}
doc.writeAttribute("oneStringValue", atype.getOneStringValue());
doc.writeAttribute("zeroStringValue", atype.getZeroStringValue());
writeNameDescription(doc, atype);
writeUnitSet(doc, atype.getUnitSet());
if (atype.getEncoding() != null) {
writeDataEncoding(doc, atype.getEncoding());
}
doc.writeEndElement();
}
private void writeBinaryArgumentType(XMLStreamWriter doc, BinaryArgumentType atype)
throws XMLStreamException {
doc.writeStartElement("BinaryArgumentType");
if (atype.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, StringConverter.arrayToHexString(atype.getInitialValue()));
}
writeNameDescription(doc, atype);
writeUnitSet(doc, atype.getUnitSet());
if (atype.getEncoding() != null) {
writeDataEncoding(doc, atype.getEncoding());
}
doc.writeEndElement();
}
private void writeAbsoluteTimeArgumentType(XMLStreamWriter doc, AbsoluteTimeArgumentType atype)
throws XMLStreamException {
doc.writeStartElement("AbsoluteTimeArgumentType");
if (atype.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, atype.getInitialValue());
}
writeNameDescription(doc, atype);
writeUnitSet(doc, atype.getUnitSet());
if (atype.getEncoding() != null) {
doc.writeStartElement(ELEM_ENCODING);
if (atype.getScale() != 1) {
doc.writeAttribute("scale", Double.toString(atype.getScale()));
}
if (atype.getOffset() != 0) {
doc.writeAttribute("offset", Double.toString(atype.getScale()));
}
writeDataEncoding(doc, atype.getEncoding());
doc.writeEndElement();// Encoding
}
writeReferenceTime(doc, atype.getReferenceTime());
doc.writeEndElement();// AbsoluteTimeArgumentType
}
private static void writeAggregateArgumentType(XMLStreamWriter doc, AggregateArgumentType atype)
throws XMLStreamException {
doc.writeStartElement("AggregateArgumentType");
writeAggregateDataType(doc, atype);
doc.writeEndElement();
}
private void writeDimensionList(XMLStreamWriter doc, List size) throws XMLStreamException {
doc.writeStartElement("DimensionList");
for (IntegerValue iv : size) {
/*
* doc.writeStartElement("Dimension");
* writeIntegerValue(doc, "StartingIndex", new FixedIntegerValue(0));
* writeIntegerValue(doc, "EndingIndex", iv-1);
* doc.writeEndElement();
*/
// the code above is commented out because we do not have a way to compute the EndIndex as size-1 for
// DynamicValues.
// The Size element is not part of XSD but it is supported by Yamcs
writeIntegerValue(doc, "Size", iv);
}
doc.writeEndElement();
}
private void writeIntegerValue(XMLStreamWriter doc, String elementName, IntegerValue iv)
throws XMLStreamException {
doc.writeStartElement(elementName);
if (iv instanceof FixedIntegerValue) {
doc.writeStartElement("FixedValue");
FixedIntegerValue fiv = (FixedIntegerValue) iv;
doc.writeCharacters(Long.toString(fiv.getValue()));
doc.writeEndElement();
} else if (iv instanceof DynamicIntegerValue) {
doc.writeStartElement("DynamicValue");
DynamicIntegerValue div = (DynamicIntegerValue) iv;
writeParameterInstanceRef(doc, ELEM_PARAMETER_INSTANCE_REF, div.getParameterInstanceRef());
doc.writeEndElement();
}
doc.writeEndElement();
}
private void writeNameReferenceAttribute(XMLStreamWriter doc, String attrName, NameDescription name)
throws XMLStreamException {
doc.writeAttribute(attrName, getNameReference(name));
}
private void writeParameterInstanceRef(XMLStreamWriter doc, String elementName, ParameterInstanceRef pinstRef)
throws XMLStreamException {
doc.writeStartElement(elementName);
doc.writeAttribute(ATTR_PARAMETER_REF, getNameReference(pinstRef));
if (pinstRef.getInstance() != 0) {
doc.writeAttribute("instance", Integer.toString(pinstRef.getInstance()));
}
if (!pinstRef.useCalibratedValue()) {
doc.writeAttribute("useCalibratedValue", "false");
}
doc.writeEndElement();
}
// write a parameter reference as an argument reference
private void writeParameterInstanceRef(XMLStreamWriter doc, String elementName, ArgumentInstanceRef pref)
throws XMLStreamException {
doc.writeStartElement(elementName);
doc.writeAttribute(ATTR_PARAMETER_REF, Mdb.YAMCS_CMDARG_SPACESYSTEM_NAME + "/" + pref.getName());
if (!pref.useCalibratedValue()) {
doc.writeAttribute("useCalibratedValue", "false");
}
doc.writeEndElement();
}
private void writeDataEncoding(XMLStreamWriter doc, DataEncoding encoding) throws XMLStreamException {
if (encoding instanceof IntegerDataEncoding) {
writeIntegerDataEncoding(doc, (IntegerDataEncoding) encoding);
} else if (encoding instanceof FloatDataEncoding) {
writeFloatDataEncoding(doc, (FloatDataEncoding) encoding);
} else if (encoding instanceof StringDataEncoding) {
writeStringDataEncoding(doc, (StringDataEncoding) encoding);
} else if (encoding instanceof BinaryDataEncoding) {
writeBinaryDataEncoding(doc, (BinaryDataEncoding) encoding);
} else {
log.warn("Unexpected data encoding " + encoding.getClass());
}
}
private void writeIntegerDataEncoding(XMLStreamWriter doc, IntegerDataEncoding encoding)
throws XMLStreamException {
doc.writeStartElement("IntegerDataEncoding");
if (encoding.getByteOrder() != ByteOrder.BIG_ENDIAN) {
doc.writeAttribute("byteOrder", "leastSignificantByteFirst");
}
switch (encoding.getEncoding()) {
case ONES_COMPLEMENT:
doc.writeAttribute(ATTR_ENCODING, "onesComplement");
break;
case SIGN_MAGNITUDE:
doc.writeAttribute(ATTR_ENCODING, "signMagnitude");
break;
case TWOS_COMPLEMENT:
doc.writeAttribute(ATTR_ENCODING, "twosComplement");
break;
case UNSIGNED:
doc.writeAttribute(ATTR_ENCODING, "unsigned");
break;
default:
log.warn("Unexpected encoding " + encoding);
}
doc.writeAttribute(ATTR_SIZE_IN_BITS, Integer.toString(encoding.getSizeInBits()));
writeNumericDataEncodingCommonProps(doc, encoding);
doc.writeEndElement();// IntegerDataEncoding
}
private void writeNumericDataEncodingCommonProps(XMLStreamWriter doc, NumericDataEncoding encoding)
throws XMLStreamException {
if (encoding.getDefaultCalibrator() != null) {
doc.writeStartElement("DefaultCalibrator");
writeCalibrator(doc, encoding.getDefaultCalibrator());
doc.writeEndElement();// DefaultCalibrator
}
if (encoding.getContextCalibratorList() != null) {
doc.writeStartElement("ContextCalibratorList");
for (ContextCalibrator cc : encoding.getContextCalibratorList()) {
doc.writeStartElement("ContextCalibrator");
doc.writeStartElement("ContextMatch");
writeMatchCriteria(doc, cc.getContextMatch());
doc.writeEndElement();// ContextMatch
doc.writeStartElement("Calibrator");
writeCalibrator(doc, cc.getCalibrator());
doc.writeEndElement();// Calibrator
doc.writeEndElement();// ContextCalibrator
}
doc.writeEndElement();// ContextCalibratorList
}
}
private void writeCalibrator(XMLStreamWriter doc, Calibrator calibrator) throws XMLStreamException {
if (calibrator instanceof PolynomialCalibrator) {
doc.writeStartElement("PolynomialCalibrator");
double[] coefficients = ((PolynomialCalibrator) calibrator).getCoefficients();
for (int i = 0; i < coefficients.length; i++) {
doc.writeStartElement("Term");
doc.writeAttribute("exponent", Integer.toString(i));
doc.writeAttribute("coefficient", Double.toString(coefficients[i]));
doc.writeEndElement();// Term
}
doc.writeEndElement();// PolynomialCalibrator
} else if (calibrator instanceof SplineCalibrator) {
doc.writeStartElement("SplineCalibrator");
// doc.writeAttribute("order", "1");
for (SplinePoint sp : ((SplineCalibrator) calibrator).getPoints()) {
doc.writeStartElement("SplinePoint");
doc.writeAttribute("raw", Double.toString(sp.getRaw()));
doc.writeAttribute("calibrated", Double.toString(sp.getCalibrated()));
doc.writeEndElement();// SplinePoint
}
doc.writeEndElement();
} else if (calibrator instanceof MathOperationCalibrator) {
doc.writeStartElement("MathOperationCalibrator");
writeMathOperation(doc, (MathOperationCalibrator) calibrator);
doc.writeEndElement();// MathOperationCalibrator
} else {
log.error("Unsupported calibrator type " + calibrator.getClass());
}
}
private void writeMathOperation(XMLStreamWriter doc, MathOperation mathOp) throws XMLStreamException {
for (MathOperation.Element me : mathOp.getElementList()) {
doc.writeStartElement(me.getType().xtceName());
if (me.getParameterInstanceRef() != null) {
doc.writeAttribute(ATTR_PARAMETER_REF, getNameReference(me.getParameterInstanceRef()));
}
if (me.getType() == ElementType.OPERATOR || me.getType() == ElementType.VALUE_OPERAND) {
doc.writeCharacters(me.toString());
}
doc.writeEndElement();
}
}
private void writeFloatDataEncoding(XMLStreamWriter doc, FloatDataEncoding encoding)
throws XMLStreamException {
doc.writeStartElement(ELEM_FLOAT_DATA_ENCODING);
doc.writeAttribute(ATTR_ENCODING, encoding.getEncoding().name());
doc.writeAttribute(ATTR_SIZE_IN_BITS, Integer.toString(encoding.getSizeInBits()));
if (encoding.getByteOrder() != ByteOrder.BIG_ENDIAN) {
doc.writeAttribute("byteOrder", "leastSignificantByteFirst");
}
writeNumericDataEncodingCommonProps(doc, encoding);
doc.writeEndElement();
}
private static void writeStringDataEncoding(XMLStreamWriter doc, StringDataEncoding encoding)
throws XMLStreamException {
doc.writeStartElement("StringDataEncoding");
if (!"UTF-8".equals(encoding.getEncoding())) {
doc.writeAttribute(ATTR_ENCODING, encoding.getEncoding());
}
if (encoding.getSizeInBits() > 0) {
doc.writeStartElement(ELEM_SIZE_IN_BITS);
doc.writeStartElement("Fixed");
doc.writeStartElement("FixedValue");
doc.writeCharacters(Integer.toString(encoding.getSizeInBits()));
doc.writeEndElement();
doc.writeEndElement();
if (encoding.getSizeType() == SizeType.LEADING_SIZE) {
doc.writeStartElement("LeadingSize");
doc.writeAttribute("sizeInBitsOfSizeTag", Integer.toString(encoding.getSizeInBitsOfSizeTag()));
doc.writeEndElement();
} else if (encoding.getSizeType() == SizeType.TERMINATION_CHAR) {
doc.writeStartElement("TerminationChar");
doc.writeCharacters(Integer.toHexString(encoding.getTerminationChar()));
doc.writeEndElement();
}
doc.writeEndElement();// SizeInBits
} else {
doc.writeStartElement(ELEM_VARIABLE);
// This attribute is required
long maxSizeInBits = encoding.getMaxSizeInBytes() * 8L;
if (maxSizeInBits > 0) {
doc.writeAttribute("maxSizeInBits", Long.toString(maxSizeInBits));
} else {
doc.writeAttribute("maxSizeInBits", "20000"); // Just set it high.
}
// Required element
doc.writeStartElement("DynamicValue");
doc.writeStartElement("ParameterInstanceRef");
var dynamicIntegerValue = encoding.getDynamicBufferSize();
if (dynamicIntegerValue != null) {
doc.writeAttribute("parameterRef", dynamicIntegerValue.getParameterInstanceRef().getName());
} else {
doc.writeAttribute("parameterRef", XtceStaxReader.IGNORED_DYNAMIC_VALUE
.getParameterInstanceRef().getParameter().getName());
}
doc.writeEndElement(); // ParameterInstanceRef
doc.writeEndElement(); // DynamicValue
if (encoding.getSizeType() == SizeType.LEADING_SIZE) {
doc.writeStartElement("LeadingSize");
doc.writeAttribute("sizeInBitsOfSizeTag", Integer.toString(encoding.getSizeInBitsOfSizeTag()));
doc.writeEndElement();
} else if (encoding.getSizeType() == SizeType.TERMINATION_CHAR) {
doc.writeStartElement("TerminationChar");
// hexBinary requires multiples of 2 hex digits
var hex = Integer.toHexString(encoding.getTerminationChar());
if (hex.length() % 2 == 0) {
doc.writeCharacters(hex);
} else {
doc.writeCharacters("0" + hex);
}
doc.writeEndElement();
}
doc.writeEndElement(); // Variable
}
doc.writeEndElement();// StringDataEncoding
}
private void writeBinaryDataEncoding(XMLStreamWriter doc, BinaryDataEncoding encoding)
throws XMLStreamException {
doc.writeStartElement("BinaryDataEncoding");
doc.writeStartElement(ELEM_SIZE_IN_BITS);
doc.writeStartElement("FixedValue");
doc.writeCharacters(Integer.toString(encoding.getSizeInBits()));
doc.writeEndElement();
doc.writeEndElement();// SizeInBits
if (encoding.getFromBinaryTransformAlgorithm() != null) {
writeCustomAlgorithm(doc, (CustomAlgorithm) encoding.getFromBinaryTransformAlgorithm(),
"FromBinaryTransformAlgorithm", true);
}
if (encoding.getToBinaryTransformAlgorithm() != null) {
writeCustomAlgorithm(doc, (CustomAlgorithm) encoding.getToBinaryTransformAlgorithm(),
"ToBinaryTransformAlgorithm", true);
}
doc.writeEndElement();// BinaryDataEncoding
}
private void writeStringParameterType(XMLStreamWriter doc, StringParameterType ptype)
throws XMLStreamException {
doc.writeStartElement("StringParameterType");
writeNameDescription(doc, ptype);
writeUnitSet(doc, ptype.getUnitSet());
if (ptype.getEncoding() != null) {
writeDataEncoding(doc, ptype.getEncoding());
}
doc.writeEndElement();
}
private static void writeNameDescription(XMLStreamWriter doc, NameDescription nameDescription)
throws XMLStreamException {
doc.writeAttribute("name", nameDescription.getName());
if (nameDescription.getShortDescription() != null) {
doc.writeAttribute("shortDescription", nameDescription.getShortDescription());
}
if (nameDescription.getLongDescription() != null) {
doc.writeStartElement("LongDescription");
doc.writeCharacters(nameDescription.getLongDescription());
doc.writeEndElement();
}
if (nameDescription.getAliasSet().size() > 0) {
doc.writeStartElement("AliasSet");
for (Entry alias : nameDescription.getAliasSet().getAliases().entrySet()) {
doc.writeStartElement("Alias");
doc.writeAttribute("nameSpace", alias.getKey());
doc.writeAttribute("alias", alias.getValue());
doc.writeEndElement();
}
doc.writeEndElement();
}
List l = nameDescription.getAncillaryData();
if (l != null) {
writeAncillaryData(doc, l);
}
}
private static void writeUnitSet(XMLStreamWriter doc, List unitSet) throws XMLStreamException {
doc.writeStartElement("UnitSet");
for (UnitType unitType : unitSet) {
doc.writeStartElement("Unit");
if (unitType.getPower() != 1) {
doc.writeAttribute("power", Double.toString(unitType.getPower()));
}
if (!unitType.getFactor().equals("1")) {
doc.writeAttribute("factor", unitType.getFactor());
}
if (unitType.getDescription() != null) {
doc.writeAttribute("description", unitType.getDescription());
}
doc.writeCharacters(unitType.getUnit());
doc.writeEndElement();
}
doc.writeEndElement();
}
private void writeMetaCommand(XMLStreamWriter doc, MetaCommand command) throws XMLStreamException {
doc.writeStartElement("MetaCommand");
if (command.isAbstract()) {
doc.writeAttribute("abstract", "true");
}
writeNameDescription(doc, command);
if (command.getBaseMetaCommand() != null) {
doc.writeStartElement("BaseMetaCommand");
doc.writeAttribute("metaCommandRef", getNameReference(command.getBaseMetaCommand()));
if (command.getArgumentAssignmentList() != null) {
doc.writeStartElement("ArgumentAssignmentList");
for (ArgumentAssignment aa : command.getArgumentAssignmentList()) {
writeArgumentAssignemnt(doc, aa);
}
doc.writeEndElement();
}
doc.writeEndElement();// BaseMetaCommand
}
if (command.getArgumentList() != null && !command.getArgumentList().isEmpty()) {
doc.writeStartElement("ArgumentList");
for (Argument arg : command.getArgumentList()) {
writeArgument(doc, arg);
}
doc.writeEndElement();
}
if (command.getCommandContainer() != null) {
writeCommandContainer(doc, command.getCommandContainer());
}
if (command.hasTransmissionConstraints()) {
doc.writeStartElement("TransmissionConstraintList");
for (TransmissionConstraint constraint : command.getTransmissionConstraintList()) {
writeTransmissionConstraint(doc, constraint);
}
doc.writeEndElement();
}
if (command.getDefaultSignificance() != null) {
writeSignificance(doc, command.getDefaultSignificance(), "DefaultSignificance");
}
if (command.hasCommandVerifiers()) {
doc.writeStartElement("VerifierSet");
for (CommandVerifier verifier : command.getCommandVerifiers()) {
writeCommandVerifier(doc, verifier);
}
doc.writeEndElement();
}
doc.writeEndElement();// MetaCommand
}
private void writeSignificance(XMLStreamWriter doc, Significance significance, String elementName)
throws XMLStreamException {
doc.writeStartElement(elementName);
if (significance.getReasonForWarning() != null) {
doc.writeAttribute("reasonForWarning", significance.getReasonForWarning());
}
doc.writeAttribute("consequenceLevel", significance.getConsequenceLevel().xtceAlias());
doc.writeEndElement();
}
private void writeArgumentAssignemnt(XMLStreamWriter doc, ArgumentAssignment aa) throws XMLStreamException {
doc.writeStartElement("ArgumentAssignment");
doc.writeAttribute("argumentName", aa.getArgumentName());
doc.writeAttribute("argumentValue", aa.getArgumentValue());
doc.writeEndElement();
}
private void writeArgument(XMLStreamWriter doc, Argument argument) throws XMLStreamException {
doc.writeStartElement("Argument");
writeNameReferenceAttribute(doc, "argumentTypeRef", (NameDescription) argument.getArgumentType());
writeNameDescription(doc, argument);
if (argument.getInitialValue() != null) {
doc.writeAttribute(ATTR_INITIAL_VALUE, argument.getArgumentType().toString(argument.getInitialValue()));
}
doc.writeEndElement();
}
private void writeSequenceContainer(XMLStreamWriter doc, SequenceContainer container) throws XMLStreamException {
doc.writeStartElement("SequenceContainer");
writeNameDescription(doc, container);
doc.writeStartElement("EntryList");
for (SequenceEntry entry : container.getEntryList()) {
writeSequenceEntry(doc, entry);
}
doc.writeEndElement();// EntryList
if (container.getBaseContainer() != null) {
doc.writeStartElement("BaseContainer");
doc.writeAttribute("containerRef", getNameReference(container.getBaseContainer()));
if (container.getRestrictionCriteria() != null) {
doc.writeStartElement("RestrictionCriteria");
writeMatchCriteria(doc, container.getRestrictionCriteria());
doc.writeEndElement();// RestrictionCriteria
}
doc.writeEndElement();// BaseContainer
}
doc.writeEndElement();// SequenceContainer
}
private void writeMathAlgorithm(XMLStreamWriter doc, MathAlgorithm algorithm)
throws XMLStreamException {
doc.writeStartElement("MathAlgorithm");
writeNameDescription(doc, algorithm);
doc.writeStartElement("MathOperation");
OutputParameter outp = algorithm.getOutputList().get(0);
doc.writeAttribute("outputParameterRef", getNameReference(outp.getParameter()));
writeMathOperation(doc, algorithm.getOperation());
if (algorithm.getTriggerSet() != null) {
writeTriggerSet(doc, algorithm.getTriggerSet());
}
doc.writeEndElement();// MathOperation
doc.writeEndElement();// MathAlgorithm
}
private void writeCustomAlgorithm(XMLStreamWriter doc, CustomAlgorithm algorithm, String elementName,
boolean inputOnly)
throws XMLStreamException {
doc.writeStartElement(elementName);
writeNameDescription(doc, algorithm);
if (algorithm.getAlgorithmText() != null) {
doc.writeStartElement("AlgorithmText");
doc.writeAttribute("language", algorithm.getLanguage());
doc.writeCharacters(algorithm.getAlgorithmText());
doc.writeEndElement();
}
if (!algorithm.getInputList().isEmpty()) {
doc.writeStartElement("InputSet");
for (InputParameter inp : algorithm.getInputList()) {
doc.writeStartElement("InputParameterInstanceRef");
ParameterInstanceRef pref = inp.getParameterInstance();
if (pref != null) {
doc.writeAttribute(ATTR_PARAMETER_REF, getNameReference(pref));
} else {// TODO - this should be written as part of an InputArgumentInstanceRef but only such a section
// is valid in XTCE
ArgumentInstanceRef aref = inp.getArgumentRef();
doc.writeAttribute(ATTR_PARAMETER_REF, Mdb.YAMCS_CMDARG_SPACESYSTEM_NAME + "/" + aref.getName());
}
if (inp.getInputName() != null) {
doc.writeAttribute("inputName", inp.getInputName());
}
doc.writeEndElement();
}
doc.writeEndElement();// InputSet
}
// Some CustomAlgorithm uses in XTCE only allow an inputset (e.g. verifiers)
if (!inputOnly) {
if (!algorithm.getOutputList().isEmpty()) {
doc.writeStartElement("OutputSet");
for (OutputParameter outp : algorithm.getOutputList()) {
doc.writeStartElement("OutputParameterRef");
doc.writeAttribute(ATTR_PARAMETER_REF, getNameReference(outp.getParameter()));
if (outp.getOutputName() != null) {
doc.writeAttribute("outputName", outp.getOutputName());
}
doc.writeEndElement();
}
doc.writeEndElement();// OutputSet
}
if (algorithm.getTriggerSet() != null) {
writeTriggerSet(doc, algorithm.getTriggerSet());
}
}
doc.writeEndElement();// elementName
}
private void writeTriggerSet(XMLStreamWriter doc, TriggerSetType triggerSet) throws XMLStreamException {
doc.writeStartElement("TriggerSet");
for (OnParameterUpdateTrigger trigger : triggerSet.getOnParameterUpdateTriggers()) {
doc.writeStartElement("OnParameterUpdateTrigger");
doc.writeAttribute(ATTR_PARAMETER_REF, getNameReference(trigger.getParameter()));
doc.writeEndElement();
}
for (OnPeriodicRateTrigger trigger : triggerSet.getOnPeriodicRateTriggers()) {
doc.writeStartElement("OnPeriodicRateTrigger");
doc.writeAttribute("fireRateInSeconds", Double.toString(trigger.getFireRate() / 1000.0));
doc.writeEndElement();
}
doc.writeEndElement();// TriggerSet
}
private static void writeAncillaryData(XMLStreamWriter doc, List l) throws XMLStreamException {
doc.writeStartElement("AncillaryDataSet");
for (AncillaryData ad : l) {
doc.writeStartElement("AncillaryData");
writeAttributeIfNotNull(doc, "name", ad.getName());
writeAttributeIfNotNull(doc, "mimeType", ad.getMimeType());
if (ad.getHref() != null) {
doc.writeAttribute("href", ad.getHref().toString());
}
writeCharactersIfNotNull(doc, ad.getValue());
doc.writeEndElement();
}
doc.writeEndElement();
}
private void writeSequenceEntry(XMLStreamWriter doc, SequenceEntry entry) throws XMLStreamException {
if (entry instanceof ArrayParameterEntry) {
doc.writeStartElement("ArrayParameterRefEntry");
doc.writeAttribute(ATTR_PARAMETER_REF, getNameReference(((ArrayParameterEntry) entry).getParameter()));
} else if (entry instanceof ParameterEntry) {
doc.writeStartElement("ParameterRefEntry");
doc.writeAttribute(ATTR_PARAMETER_REF, getNameReference(((ParameterEntry) entry).getParameter()));
} else if (entry instanceof ContainerEntry) {
doc.writeStartElement("ContainerRefEntry");
doc.writeAttribute("containerRef", getNameReference(((ContainerEntry) entry).getContainer()));
} else if (entry instanceof ArgumentEntry) {
doc.writeStartElement("ArgumentRefEntry");
doc.writeAttribute("argumentRef", ((ArgumentEntry) entry).getArgument().getName());
} else if (entry instanceof FixedValueEntry) {
doc.writeStartElement("FixedValueEntry");
FixedValueEntry fve = (FixedValueEntry) entry;
if (fve.getName() != null) {
doc.writeAttribute("name", fve.getName());
}
doc.writeAttribute("binaryValue", StringConverter.arrayToHexString(fve.getBinaryValue()));
doc.writeAttribute(ATTR_SIZE_IN_BITS, Integer.toString(fve.getSizeInBits()));
} else {
log.error("Unknown sequence entry type " + entry.getClass() + " used for " + entry);
return;
}
if (entry.getReferenceLocation() != ReferenceLocationType.PREVIOUS_ENTRY
|| entry.getLocationInContainerInBits() != 0) {
doc.writeStartElement("LocationInContainerInBits");
doc.writeAttribute("referenceLocation", entry.getReferenceLocation().xtceName());
doc.writeStartElement("FixedValue");
doc.writeCharacters(Integer.toString(entry.getLocationInContainerInBits()));
doc.writeEndElement();// FixedValue
doc.writeEndElement();// LocationInContainerInBits
}
if (entry.getRepeatEntry() != null) {
doc.writeStartElement("RepeatEntry");
writeRepeat(doc, entry.getRepeatEntry());
doc.writeEndElement();
}
if (entry.getIncludeCondition() != null) {
doc.writeStartElement("IncludeCondition");
writeMatchCriteria(doc, entry.getIncludeCondition());
doc.writeEndElement();
}
if (entry instanceof ArrayParameterEntry) {
List dim = ((ArrayParameterEntry) entry).getSize();
if (dim != null) {
writeDimensionList(doc, dim);
}
}
doc.writeEndElement();// *RefEntry
}
private void writeRepeat(XMLStreamWriter doc, Repeat repeat) throws XMLStreamException {
writeIntegerValue(doc, "Count", repeat.getCount());
if (repeat.getOffsetSizeInBits() != 0) {
doc.writeStartElement("Offset");
doc.writeStartElement("FixedValue");
doc.writeCharacters(Integer.toString(repeat.getOffsetSizeInBits()));
doc.writeEndElement();
doc.writeEndElement();
}
}
private void writeMatchCriteria(XMLStreamWriter doc, MatchCriteria mc) throws XMLStreamException {
if (mc instanceof Comparison) {
writeComparison(doc, (Comparison) mc);
} else if (mc instanceof ComparisonList) {
writeComparisonList(doc, (ComparisonList) mc);
} else if (mc instanceof BooleanExpression) {
doc.writeStartElement("BooleanExpression");
writeBooleanExpression(doc, (BooleanExpression) mc);
doc.writeEndElement();
}
}
private void writeComparisonList(XMLStreamWriter doc, ComparisonList comparisonList) throws XMLStreamException {
doc.writeStartElement("ComparisonList");
for (Comparison c : comparisonList.getComparisonList()) {
writeComparison(doc, c);
}
doc.writeEndElement();
}
private void writeComparison(XMLStreamWriter doc, Comparison comparison) throws XMLStreamException {
doc.writeStartElement("Comparison");
ParameterOrArgumentRef ref = comparison.getRef();
if (ref instanceof ParameterInstanceRef) {
ParameterInstanceRef pref = (ParameterInstanceRef) ref;
doc.writeAttribute(ATTR_PARAMETER_REF, getNameReference(pref));
if (pref.getInstance() != 0) {
doc.writeAttribute("instance", Integer.toString(pref.getInstance()));
}
} else {
doc.writeAttribute(ATTR_PARAMETER_REF, Mdb.YAMCS_CMDARG_SPACESYSTEM_NAME + "/" + ref.getName());
}
boolean ucv = comparison.getRef().useCalibratedValue();
if (!ucv) {
doc.writeAttribute("useCalibratedValue", "false");
}
doc.writeAttribute("value", comparison.getStringValue());
if (comparison.getComparisonOperator() != OperatorType.EQUALITY) {
doc.writeAttribute("comparisonOperator", comparison.getComparisonOperator().getSymbol());
}
doc.writeEndElement();
}
private void writeBooleanExpression(XMLStreamWriter doc, BooleanExpression boolExpr) throws XMLStreamException {
if (boolExpr instanceof Condition) {
writeCondition(doc, (Condition) boolExpr);
} else if (boolExpr instanceof ANDedConditions) {
writeANDedCondition(doc, (ANDedConditions) boolExpr);
} else if (boolExpr instanceof ORedConditions) {
writeORedCondition(doc, (ORedConditions) boolExpr);
}
}
private void writeCondition(XMLStreamWriter doc, Condition condition) throws XMLStreamException {
doc.writeStartElement(ELEM_CONDITION);
ParameterOrArgumentRef ref = condition.getLeftRef();
if (ref instanceof ParameterInstanceRef) {
writeParameterInstanceRef(doc, ELEM_PARAMETER_INSTANCE_REF, (ParameterInstanceRef) ref);
} else {
writeParameterInstanceRef(doc, ELEM_PARAMETER_INSTANCE_REF, (ArgumentInstanceRef) ref);
}
doc.writeStartElement(ELEM_COMPARISON_OPERATOR);
doc.writeCharacters(condition.getComparisonOperator().getSymbol());
doc.writeEndElement();
ref = condition.getRightRef();
if (ref instanceof ParameterInstanceRef) {
writeParameterInstanceRef(doc, ELEM_PARAMETER_INSTANCE_REF, (ParameterInstanceRef) ref);
} else if (ref instanceof ArgumentInstanceRef) {
writeParameterInstanceRef(doc, ELEM_PARAMETER_INSTANCE_REF, (ArgumentInstanceRef) ref);
} else {
doc.writeStartElement(ELEM_VALUE);
doc.writeCharacters(condition.getRightValue());
doc.writeEndElement();
}
doc.writeEndElement();
}
private void writeANDedCondition(XMLStreamWriter doc, ANDedConditions condition) throws XMLStreamException {
doc.writeStartElement("ANDedConditions");
for (BooleanExpression boolExpr : condition.getExpressionList()) {
writeBooleanExpression(doc, boolExpr);
}
doc.writeEndElement();
}
private void writeORedCondition(XMLStreamWriter doc, ORedConditions condition) throws XMLStreamException {
doc.writeStartElement("ORedConditions");
for (BooleanExpression boolExpr : condition.getExpressionList()) {
writeBooleanExpression(doc, boolExpr);
}
doc.writeEndElement();
}
private void writeCommandContainer(XMLStreamWriter doc, CommandContainer container) throws XMLStreamException {
doc.writeStartElement("CommandContainer");
doc.writeAttribute("name", container.getName());
doc.writeStartElement("EntryList");
for (SequenceEntry entry : container.getEntryList()) {
writeSequenceEntry(doc, entry);
}
doc.writeEndElement();// EntryList
if (container.getBaseContainer() != null) {
doc.writeStartElement("BaseContainer");
doc.writeAttribute("containerRef", getNameReference(container.getBaseContainer()));
if (container.getRestrictionCriteria() != null) {
doc.writeStartElement("RestrictionCriteria");
writeMatchCriteria(doc, container.getRestrictionCriteria());
doc.writeEndElement();// RestrictionCriteria
}
doc.writeEndElement();// BaseContainer
}
doc.writeEndElement();// CommandContainer
}
private void writeTransmissionConstraint(XMLStreamWriter doc, TransmissionConstraint constraint)
throws XMLStreamException {
doc.writeStartElement("TransmissionConstraint");
if (constraint.getTimeout() > 0) {
Duration d = dataTypeFactory.newDuration(constraint.getTimeout());
doc.writeAttribute("timeOut", d.toString());
}
writeMatchCriteria(doc, constraint.getMatchCriteria());
doc.writeEndElement();// TransmissionConstraint
}
private void writeCommandVerifier(XMLStreamWriter doc, CommandVerifier verifier) throws XMLStreamException {
if (!XTCE_VERIFIER_STAGES.contains(verifier.getStage())) {
log.warn("The verifier stage '{}' cannot be mapped to XTCE. Allowed XTCE stages: {}", verifier.getStage(),
XTCE_VERIFIER_STAGES);
return;
}
doc.writeStartElement(verifier.getStage() + "Verifier");
var ancillaryData = new ArrayList();
ancillaryData.add(new AncillaryData("yamcs.onSuccess",
verifier.getOnSuccess() != null ? verifier.getOnSuccess().name() : null));
ancillaryData.add(new AncillaryData("yamcs.onFail",
verifier.getOnFail() != null ? verifier.getOnFail().name() : null));
ancillaryData.add(new AncillaryData("yamcs.onTimeout",
verifier.getOnTimeout() != null ? verifier.getOnTimeout().name() : null));
writeAncillaryData(doc, ancillaryData);
switch (verifier.getType()) {
case MATCH_CRITERIA:
writeMatchCriteria(doc, verifier.getMatchCriteria());
break;
case CONTAINER:
doc.writeStartElement("ContainerRef");
doc.writeAttribute("containerRef", getNameReference(verifier.getContainerRef()));
doc.writeEndElement();
break;
case ALGORITHM:
writeCustomAlgorithm(doc, (CustomAlgorithm) verifier.getAlgorithm(), "CustomAlgorithm", true);
break;
case PARAMETER_VALUE_CHANGE:
ParameterValueChange pvc = verifier.getParameterValueChange();
doc.writeStartElement(ELEM_PARAMETER_VALUE_CHANGE);
writeParameterInstanceRef(doc, ELEM_PARAMETER_REF, pvc.getParameterRef());
doc.writeStartElement("Change");
doc.writeAttribute("value", Double.toString(pvc.getDelta()));
doc.writeEndElement();
doc.writeEndElement();// ParameterValueChange
break;
}
writeCheckWindow(doc, verifier.getCheckWindow());
if (verifier.getReturnParameter() != null) {
doc.writeStartElement("ReturnParmRef");
doc.writeAttribute(ATTR_PARAMETER_REF, getNameReference(verifier.getReturnParameter()));
doc.writeEndElement();
}
doc.writeEndElement();// verifier name (stage)
}
private void writeCheckWindow(XMLStreamWriter doc, CheckWindow cw) throws XMLStreamException {
doc.writeStartElement("CheckWindow");
if (cw.getTimeToStartChecking() >= 0) {
doc.writeAttribute("timeToStartChecking",
dataTypeFactory.newDuration(cw.getTimeToStartChecking()).toString());
}
doc.writeAttribute("timeToStopChecking",
dataTypeFactory.newDuration(cw.getTimeToStopChecking()).toString());
if (cw.getTimeWindowIsRelativeTo() != TimeWindowIsRelativeToType.LAST_VERIFIER) {
doc.writeAttribute("timeWindowIsRelativeTo", cw.getTimeWindowIsRelativeTo().toXtce());
}
doc.writeEndElement();// CheckWindow
}
private String getNameReference(ParameterInstanceRef pinstRef) {
StringBuilder sb = new StringBuilder();
sb.append(getNameReference(pinstRef.getParameter()));
if (pinstRef.getMemberPath() != null) {
for (PathElement pe : pinstRef.getMemberPath()) {
sb.append(".").append(pe.getName());
}
}
return sb.toString();
}
// converts the nd qualified name to a relative reference to the current subsystem
// if the reference is to the "/yamcs" then an absolute reference is provided instead
private String getNameReference(NameDescription nd) {
String ndqn = nd.getQualifiedName();
if (ndqn == null) { // happens for arguments
return nd.getName();
}
String ssname = currentSpaceSystem.getQualifiedName();
if (ndqn.startsWith(ssname + "/")) {
return ndqn.substring(ssname.length() + 1);
} else if (ndqn.startsWith(Mdb.YAMCS_SPACESYSTEM_NAME)) {
return ndqn;
} else {
String[] pe1 = currentSpaceSystem.getQualifiedName().split("/");
String[] pe2 = nd.getSubsystemName().split("/");
if (!pe1[1].equals(pe2[1])) {
return ndqn;
}
int k = 0;
for (k = 0; k < Math.min(pe1.length, pe2.length); k++) {
if (!pe1[k].equals(pe2[k])) {
break;
}
}
StringBuilder sb = new StringBuilder();
for (int i = k; i < pe1.length; i++) {
sb.append("../");
}
for (int i = k; i < pe2.length; i++) {
sb.append(pe2[i]).append("/");
}
sb.append(nd.getName());
return sb.toString();
}
}
private static void writeAttributeIfNotNull(XMLStreamWriter doc, String name, String value)
throws XMLStreamException {
if (value != null) {
doc.writeAttribute(name, value);
}
}
private static void writeCharactersIfNotNull(XMLStreamWriter doc, String text) throws XMLStreamException {
if (text != null) {
doc.writeCharacters(text);
}
}
}