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

Started work on NDM combined messages.

parent 319835be
......@@ -40,7 +40,7 @@
participant BufferedInputStream
participant XyzLexicalAnalyzer
participant ParseToken
participant NDMFile
participant NdmConstituent
activate Main
create DataSource
......@@ -85,9 +85,9 @@
deactivate MessageParser
end
deactivate XyzLexicalAnalyzer
create NDMFile
MessageParser -> NDMFile : build
MessageParser --> Main : NDMFile
create NdmConstituent
MessageParser -> NdmConstituent : build
MessageParser --> Main : NdmConstituent
deactivate MessageParser
deactivate Main
......
......@@ -37,6 +37,7 @@
-formatVersion
-creationDate
-originator
-messageId
}
class Metadata {
-timeSystem
......@@ -93,12 +94,14 @@
OMM, OCM, TDM, APM, and AEM
end note
abstract class NdmFile
abstract class NdmConstituent
class NdmFile
NdmFile <|-- OemFile
NdmFile <|-- OpmFile
Header "1" <--o NdmFile
Segment "*" <--o NdmFile
NdmConstituent <|-- OemFile
NdmConstituent <|-- OpmFile
Header "1" <--o NdmConstituent
Segment "*" <--o NdmConstituent
NdmConstituent "*" <--o NdmFile
}
}
......
......@@ -26,7 +26,7 @@ import org.orekit.files.ccsds.ndm.odm.opm.OpmParser;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.IERSConventions;
/** Abstract builder for all {@link NdmFile CCSDS Message} files parsers/writers.
/** Abstract builder for all {@link NdmConstituent CCSDS Message} files parsers/writers.
* @param <T> type of the builder
* @author Luc Maisonobe
* @since 11.0
......
/* 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.util.Collections;
import java.util.List;
import org.orekit.data.DataContext;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.ccsds.section.Header;
import org.orekit.files.ccsds.section.Segment;
import org.orekit.utils.IERSConventions;
/**
* Constituents of a CCSDS Navigation Data Message.
* Constituents may be Attitude Data Message (ADM), Orbit Data Message (ODM),
* Tracking Data Message (TDM)…
* Each constituent has its own header and a list of segments.
* @param <H> type of the header
* @param <S> type of the segments
* @author Bryan Cazabonne
* @since 10.2
*/
public abstract class NdmConstituent<H extends Header, S extends Segment<?, ?>> {
/** Header. */
private final H header;
/** segments list. */
private final List<S> segments;
/** IERS conventions used. */
private final IERSConventions conventions;
/** Data context. */
private final DataContext dataContext;
/**
* Constructor.
* @param header file header
* @param segments file segments
* @param conventions IERS conventions
* @param dataContext used for creating frames, time scales, etc.
*/
protected NdmConstituent(final H header, final List<S> segments,
final IERSConventions conventions, final DataContext dataContext) {
this.header = header;
this.segments = segments;
this.conventions = conventions;
this.dataContext = dataContext;
}
/**
* Get the header.
* @return header
* @since 11.0
*/
public H getHeader() {
return header;
}
/**
* Get the segments.
* @return segments
* @since 11.0
*/
public List<S> getSegments() {
return Collections.unmodifiableList(segments);
}
/**
* Get IERS conventions.
* @return IERS conventions
*/
public IERSConventions getConventions() {
if (conventions != null) {
return conventions;
} else {
throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
}
}
/**
* Get the data context.
* @return the data context used for creating frames, time scales, etc.
*/
public DataContext getDataContext() {
return dataContext;
}
}
......@@ -19,89 +19,40 @@ package org.orekit.files.ccsds.ndm;
import java.util.Collections;
import java.util.List;
import org.orekit.data.DataContext;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.ccsds.section.Header;
import org.orekit.files.ccsds.section.Segment;
import org.orekit.utils.IERSConventions;
/**
* The NDMFile (Navigation Data Message) class represents the navigation
* messages used by the CCSDS format, (i.e. the Attitude Data Message (ADM),
* the Orbit Data Message (ODM) and the Tracking Data Message (TDM)).
* It contains the information of the message's header and configuration data
* (set in the parser).
* @param <H> type of the header
* @param <S> type of the segments
* @author Bryan Cazabonne
* @since 10.2
/** CCSDS Navigation Data Message.
* This class is a container for comments and {@link NdmConstituent constituents}.
* @author Luc Maisonobe
* @since 11.0
*/
public abstract class NdmFile<H extends Header, S extends Segment<?, ?>> {
/** Header. */
private final H header;
/** segments list. */
private final List<S> segments;
public class NdmFile {
/** IERS conventions used. */
private final IERSConventions conventions;
/** File comments. */
private final List<String> comments;
/** Data context. */
private final DataContext dataContext;
/**
* Constructor.
* @param header file header
* @param segments file segments
* @param conventions IERS conventions
* @param dataContext used for creating frames, time scales, etc.
*/
protected NdmFile(final H header, final List<S> segments,
final IERSConventions conventions, final DataContext dataContext) {
this.header = header;
this.segments = segments;
this.conventions = conventions;
this.dataContext = dataContext;
}
/**
* Get the header.
* @return header
* @since 11.0
*/
public H getHeader() {
return header;
}
/** Constituents of the message. */
private final List<NdmConstituent<?, ?>> constituents;
/**
* Get the segments.
* @return segments
* @since 11.0
/** Simple constructor.
* @param comments file comments
* @param constituents constituents of the message
*/
public List<S> getSegments() {
return Collections.unmodifiableList(segments);
public NdmFile(final List<String> comments, final List<NdmConstituent<?, ?>> constituents) {
this.comments = comments;
this.constituents = constituents;
}
/**
* Get IERS conventions.
* @return IERS conventions
/** Get an unmodifiable view of the comments.
* @return unmodifiable view of the comment
*/
public IERSConventions getConventions() {
if (conventions != null) {
return conventions;
} else {
throw new OrekitException(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS);
}
public List<String> getComments() {
return Collections.unmodifiableList(comments);
}
/**
* Get the data context.
* @return the data context used for creating frames, time scales, etc.
/** Get an unmodifiable view of the constituents.
* @return unmodifiable view of the constituents
*/
public DataContext getDataContext() {
return dataContext;
public List<NdmConstituent<?, ?>> getConstituents() {
return Collections.unmodifiableList(constituents);
}
}
/* 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.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.ccsds.section.CommentsContainer;
import org.orekit.files.ccsds.utils.FileFormat;
import org.orekit.files.ccsds.utils.lexical.ParseToken;
import org.orekit.files.ccsds.utils.lexical.XmlTokenBuilder;
import org.orekit.files.ccsds.utils.parsing.AbstractMessageParser;
import org.orekit.files.ccsds.utils.parsing.ErrorState;
/** A parser for the CCSDS NDM (Navigation Data Message).
* @author Luc Maisonobe
* @since 11.0
*/
public class NdmParser extends AbstractMessageParser<NdmFile> {
/** Builder for the constituents parsers. */
private final ParserBuilder builder;
/** Current constituent parser. */
private AbstractMessageParser<? extends NdmConstituent<?, ?>> constituentParser;
/** Container for comments. */
private CommentsContainer comments;
/** Container for constituents. */
private List<NdmConstituent<?, ?>> constituents;
/** Simple constructor.
* <p>
* Calling this constructor directly is not recommended. Users should rather use
* {@link org.orekit.files.ccsds.ndm.ParserBuilder#buildNdmParser()
* parserBuilder.buildNdmParser()}.
* </p>
* @param builder builder for the constituents parsers
*/
public NdmParser(final ParserBuilder builder) {
super(NdmStructureKey.ndm.name(), null);
this.builder = builder;
}
/** {@inheritDoc} */
@Override
public Map<String, XmlTokenBuilder> getSpecialXmlElementsBuilders() {
final Map<String, XmlTokenBuilder> builders = super.getSpecialXmlElementsBuilders();
// special handling of root elements for all constituents
builders.putAll(builder.buildTdmParser().getSpecialXmlElementsBuilders());
builders.putAll(builder.buildOpmParser().getSpecialXmlElementsBuilders());
builders.putAll(builder.buildOmmParser().getSpecialXmlElementsBuilders());
builders.putAll(builder.buildOemParser().getSpecialXmlElementsBuilders());
builders.putAll(builder.buildOcmParser().getSpecialXmlElementsBuilders());
builders.putAll(builder.buildApmParser().getSpecialXmlElementsBuilders());
builders.putAll(builder.buildAemParser().getSpecialXmlElementsBuilders());
return builders;
}
/** {@inheritDoc} */
@Override
public void reset(final FileFormat fileFormat) {
reset(fileFormat, this::processStructureToken);
setFallback(new ErrorState());
constituentParser = null;
comments = new CommentsContainer();
constituents = new ArrayList<>();
}
/** {@inheritDoc} */
@Override
public NdmFile build() {
// store the previous constituent if any
storeLastConstituent();
// build the file from parsed comments and constituents
return new NdmFile(comments.getComments(), constituents);
}
/**
* Add comment.
* <p>
* Comments are accepted only at start. Once
* other content is stored in the same section, comments are refused.
* </p>
* @param comment comment line
* @return true if comment was accepted
*/
public boolean addComment(final String comment) {
return comments.addComment(comment);
}
/** Store last parsed constituent.
*/
private void storeLastConstituent() {
if (constituentParser != null) {
constituents.add(constituentParser.build());
}
constituentParser = null;
}
/** Prepare parsing of a constituent.
* <p>
* Returning false allows the root element of the constituent to be handled by the dedicated parser
* </p>
* otherwise it is leaving the section
* @param build builder for constituent parser
* @return always return false!
*/
boolean manageConstituent(final Function<ParserBuilder, AbstractMessageParser<? extends NdmConstituent<?, ?>>> build) {
// as we have started parsing constituents, we cannot accept any further comments
comments.refuseFurtherComments();
// store the previous constituent if any
storeLastConstituent();
// create a parser for the constituent
constituentParser = build.apply(builder);
constituentParser.reset(getFileFormat());
// delegate to the constituent parser the parsing of upcoming tokens
// (including the current one that will be rejected below)
anticipateNext(constituentParser.getCurrent());
setFallback(this::processStructureToken);
// reject current token, so it will be parsed by the constituent just built
return false;
}
/** Process one structure token.
* @param token token to process
* @return true if token was processed, false otherwise
*/
private boolean processStructureToken(final ParseToken token) {
if (getFileFormat() == FileFormat.KVN) {
// NDM combined instantiation can only be formatted as XML messages
throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, token.getFileName());
}
try {
return NdmStructureKey.valueOf(token.getName()).process(token, this);
} catch (IllegalArgumentException iae) {
// token has not been recognized
return false;
}
}
}
/* 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 org.orekit.files.ccsds.utils.lexical.ParseToken;
import org.orekit.files.ccsds.utils.lexical.TokenType;
/** Keywords for NDM structure in XML files.
* @author Luc Maisonobe
* @since 11.0
*/
enum NdmStructureKey {
/** Comment entry. */
COMMENT((token, parser) ->
token.getType() == TokenType.ENTRY ? parser.addComment(token.getContentAsNormalizedString()) : true),
/** Root element. */
ndm((token, parser) -> true),
/** TDM constituent. */
CCSDS_TDM_VERSION((token, parser) -> parser.manageConstituent(builder -> builder.buildTdmParser())),
/** OPM constituent. */
CCSDS_OPM_VERSION((token, parser) -> parser.manageConstituent(builder -> builder.buildOpmParser())),
/** OMM constituent. */
CCSDS_OMM_VERSION((token, parser) -> parser.manageConstituent(builder -> builder.buildOmmParser())),
/** OEM constituent. */
CCSDS_OEM_VERSION((token, parser) -> parser.manageConstituent(builder -> builder.buildOemParser())),
/** OCM constituent. */
CCSDS_OCM_VERSION((token, parser) -> parser.manageConstituent(builder -> builder.buildOcmParser())),
/** APM constituent. */
CCSDS_APM_VERSION((token, parser) -> parser.manageConstituent(builder -> builder.buildApmParser())),
/** AEM constituent. */
CCSDS_AEM_VERSION((token, parser) -> parser.manageConstituent(builder -> builder.buildAemParser()));
/** Processing method. */
private final TokenProcessor processor;
/** Simple constructor.
* @param processor processing method
*/
NdmStructureKey(final TokenProcessor processor) {
this.processor = processor;
}
/** Process one token.
* @param token token to process
* @param parser OPM file parser
* @return true of token was accepted
*/
public boolean process(final ParseToken token, final NdmParser parser) {
return processor.process(token, parser);
}
/** Interface for processing one token. */
interface TokenProcessor {
/** Process one token.
* @param token token to process
* @param parser NDM file parser
* @return true of token was accepted
*/
boolean process(ParseToken token, NdmParser parser);
}
}
......@@ -263,6 +263,13 @@ public class ParserBuilder extends AbstractBuilder<ParserBuilder> {
return rangeUnitsConverter;
}
/** Build a parser for {@link org.orekit.files.ccsds.ndm.NdmFile Navigation Data Messages}.
* @return a new parser
*/
public NdmParser buildNdmParser() {
return new NdmParser(this);
}
/** Build a parser for {@link org.orekit.files.ccsds.ndm.odm.opm.OpmFile Orbit Parameters Messages}.
* @return a new parser
*/
......
......@@ -31,7 +31,7 @@ import org.orekit.files.ccsds.ndm.tdm.TdmWriter;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.IERSConventions;
/** Builder for all {@link NdmFile CCSDS Message} files writers.
/** Builder for all {@link NdmConstituent CCSDS Message} files writers.
* <p>
* This builder can be used for building all CCSDS Messages writers types.
* It is particularly useful in multi-threaded context as writers cannot
......
......@@ -23,12 +23,12 @@ import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.orekit.data.DataContext;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.ccsds.ndm.NdmFile;
import org.orekit.files.ccsds.ndm.NdmConstituent;
import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
import org.orekit.files.ccsds.utils.lexical.ParseToken;
import org.orekit.files.ccsds.utils.lexical.TokenType;
import org.orekit.files.ccsds.utils.lexical.XmlTokenBuilder;
import org.orekit.files.ccsds.utils.parsing.AbstractMessageParser;
import org.orekit.files.ccsds.utils.parsing.AbstractConstituentParser;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.IERSConventions;
......@@ -48,8 +48,8 @@ import org.orekit.utils.IERSConventions;
* @author Luc Maisonobe
* @since 11.0