Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
## [3.1.0] - TBC

### Enhancements
- [#254](https://github.com/nHapiNET/nHapi/pull/254) Add `UnexpectedSegmentBehaviour` Options, ported from hapi
- [#251](https://github.com/nHapiNET/nHapi/pull/251) Fix concurrency issues with `PipeParser`, `StructureDefinition`, `GenericMessage` and `Escape`.
- [#250](https://github.com/nHapiNET/nHapi/pull/250) Add new options `DefaultObx2Type` and `InvalidObx2Type` to `ParserOptions`, ported from nhapi. (fixes [#63](https://github.com/nHapiNET/nHapi/issues/63))
- [#240](https://github.com/nHapiNET/nHapi/pull/240) Add support for `NonGreedyMode` by introducing `ParserOptions` ported from hapi. (fixes [#65](https://github.com/nHapiNET/nHapi/issues/65) [#232](https://github.com/nHapiNET/nHapi/issues/232))
Expand Down
10 changes: 6 additions & 4 deletions src/NHapi.Base/Parser/LegacyPipeParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,10 +477,12 @@ public virtual void Parse(ISegment destination, string segment, EncodingCharacte
/// <summary> <p>Returns a minimal amount of data from a message string, including only the
/// data needed to send a response to the remote system. This includes the
/// following fields:
/// <ul><li>field separator</li>
/// <li>encoding characters</li>
/// <li>processing ID</li>
/// <li>message control ID</li></ul>
/// <list type="bullet">
/// <item><description>field separator</description></item>
/// <item><description>encoding characters</description></item>
/// <item><description>processing ID</description></item>
/// <item><description>message control ID</description></item>
/// </list>
/// This method is intended for use when there is an error parsing a message,
/// (so the Message object is unavailable) but an error message must be sent
/// back to the remote system including some of the information in the inbound
Expand Down
70 changes: 37 additions & 33 deletions src/NHapi.Base/Parser/MessageIterator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,28 +55,33 @@ public MessageIterator(
this.parserOptions = parserOptions;
}

/// <summary> <p>Returns the next node in the message. Sometimes the next node is
/// <summary>
/// <para>
/// Returns the next node in the message. Sometimes the next node is
/// ambiguous. For example at the end of a repeating group, the next node
/// may be the first segment in the next repetition of the group, or the
/// next sibling, or an undeclared segment locally added to the group's end.
/// Cases like this are disambiguated using getDirection(), which returns
/// Cases like this are disambiguated using <see cref="Direction"/>, which returns
/// the name of the structure that we are "iterating towards".
/// Usually we are "iterating towards" a segment of a certain name because we
/// have a segment string that we would like to parse into that node.
/// Here are the rules: </p>
/// <ol><li>If at a group, next means first child.</li>
/// <li>If at a non-repeating segment, next means next "position"</li>
/// <li>If at a repeating segment: if segment name matches
/// direction then next means next rep, otherwise next means next "position".</li>
/// <li>If at a segment within a group (not at the end of the group), next "position"
/// means next sibling</li>
/// <li>If at the end of a group: If name of group or any of its "first
/// Here are the rules:
/// </para>
/// <list type="bullet">
/// <item><description>If at a group, next means first child.</description></item>
/// <item><description>If at a non-repeating segment, next means next "position"</description></item>
/// <item><description>If at a repeating segment: if segment name matches
/// direction then next means next rep, otherwise next means next "position".</description></item>
/// <item><description>If at a segment within a group (not at the end of the group), next "position"
/// means next sibling</description></item>
/// <item><description>If at the end of a group: If name of group or any of its "first
/// descendants" matches direction, then next position means next rep of group. Otherwise
/// if direction matches name of next sibling of the group, or any of its first
/// descendants, next position means next sibling of the group. Otherwise, next means a
/// new segment added to the group (with a name that matches "direction"). </li>
/// <li>"First descendants" means first child, or first child of the first child,
/// or first child of the first child of the first child, etc. </li> </ol>
/// new segment added to the group (with a name that matches "direction").</description></item>
/// <item><description>"First descendants" means first child, or first child of the first child,
/// or first child of the first child of the first child, etc.</description></item>
/// </list>
/// </summary>
public virtual object Current
{
Expand Down Expand Up @@ -233,26 +238,25 @@ private void AddNonStandardSegmentAtCurrentPosition()
Log.Debug(
$"Creating non standard segment {direction} on group: {GetCurrentPosition().StructureDefinition.Parent.Name}");

// TODO: make configurable like hapi?
// switch (message.getParser().getParserConfiguration().getUnexpectedSegmentBehaviour())
// {
// case ADD_INLINE:
// default:
// parentDefinitionPath = new ArrayList<>(myCurrentDefinitionPath.subList(0, myCurrentDefinitionPath.size() - 1));
// parentStructure = (IGroup)navigateToStructure(parentDefinitionPath);
// break;
// case DROP_TO_ROOT:
// parentDefinitionPath = new ArrayList<>(myCurrentDefinitionPath.subList(0, 1));
// parentStructure = myMessage;
// myCurrentDefinitionPath = myCurrentDefinitionPath.subList(0, 2);
// break;
// case THROW_HL7_EXCEPTION:
// throw new Error(new HL7Exception("Found unknown segment: " + myDirection));
// }

// default hapi behaviour
var parentDefinitionPath = new List<Position>(currentDefinitionPath.GetRange(0, currentDefinitionPath.Count - 1));
var parentStructure = (IGroup)NavigateToStructure(parentDefinitionPath);
List<Position> parentDefinitionPath;
IGroup parentStructure;

switch (parserOptions.UnexpectedSegmentBehaviour)
{
case UnexpectedSegmentBehaviour.AddInline:
parentDefinitionPath = new List<Position>(currentDefinitionPath.GetRange(0, currentDefinitionPath.Count - 1));
parentStructure = (IGroup)NavigateToStructure(parentDefinitionPath);
break;
case UnexpectedSegmentBehaviour.DropToRoot:
parentDefinitionPath = new List<Position>(currentDefinitionPath.GetRange(0, 1));
parentStructure = this.message;
currentDefinitionPath = currentDefinitionPath.GetRange(0, 2);
break;
case UnexpectedSegmentBehaviour.ThrowHl7Exception:
throw new HL7Exception($"Found unknown segment: {direction}");
default:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commenting without context here, but...

is this truely the default behaviour? ie: if I added another value to UnexpectedSegmentBehaviour would I want this behaviour? If not, would suggest being expicit and including case: UnexpectedSegmentBehaviour.AddInline and then throwning an exception as the default case (UnhandledUnexpectedSegmentBehaviourException or something)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AMCN41R I did have it like that, but the static analysis recommended against it, ill see if I can dig up the message.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AMCN41R also that was the default behaviour before the config option as you can see in the diff. all I did here was make it implicitly default (ported from hapi).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AMCN41R I see what you are saying having thought about it, I will make the change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AMCN41R I had made this change.

throw new HL7Exception($"UnexpectedSegmentBehaviour.{parserOptions.UnexpectedSegmentBehaviour} is not currently handled.");
}

// Current position within parent
var currentPosition = GetCurrentPosition();
Expand Down
8 changes: 4 additions & 4 deletions src/NHapi.Base/Parser/ParserBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,10 @@ public bool SupportsEncoding(string encoding)
/// data needed to send a response to the remote system.
/// <para>This includes the following fields:</para>
/// <list type="bullet">
/// <listHeader>field separator</listHeader>
/// <item>encoding characters</item>
/// <item>processing ID</item>
/// <item>message control ID</item>
/// <item><description>field separator</description></item>
/// <item><description>encoding characters</description></item>
/// <item><description>processing ID</description></item>
/// <item><description>message control ID</description></item>
/// </list>
/// This method is intended for use when there is an error parsing a message,
/// (so the Message object is unavailable) but an error message must be sent
Expand Down
7 changes: 7 additions & 0 deletions src/NHapi.Base/Parser/ParserOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public ParserOptions()
{
DefaultObx2Type = null;
InvalidObx2Type = null;
UnexpectedSegmentBehaviour = UnexpectedSegmentBehaviour.AddInline;
NonGreedyMode = false;
}

Expand Down Expand Up @@ -49,6 +50,12 @@ public ParserOptions()
/// </example>
public string InvalidObx2Type { get; set; }

/// <summary>
/// Gets or Sets the behaviour to use when parsing a message and a nonstandard segment is found.
/// </summary>
/// <remarks>The default value is <see cref="Parser.UnexpectedSegmentBehaviour.AddInline"/>.</remarks>
public UnexpectedSegmentBehaviour UnexpectedSegmentBehaviour { get; set; }

/// <summary>
/// If set to <c>true</c> (default is <c>false</c>), pipe parser will be put in non-greedy mode. This setting
/// applies only to <see cref="PipeParser"/> and will have no effect on <see cref="XMLParser"/>.
Expand Down
29 changes: 29 additions & 0 deletions src/NHapi.Base/Parser/UnexpectedSegmentBehaviour.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace NHapi.Base.Parser
{
using NHapi.Base.Model;

/// <summary>
/// Defines the behaviour to use when an unexpected segment is discovered while parsing a message.
/// </summary>
/// <remarks>See <see cref="ParserOptions.UnexpectedSegmentBehaviour"/>.</remarks>
public enum UnexpectedSegmentBehaviour
{
/// <summary>
/// Add the segment as a <see cref="IGroup.AddNonstandardSegment(string, int)"/>
/// at the current location, even if the current location is in a child group within the message.
/// </summary>
/// <remarks>This is the default.</remarks>
AddInline,

/// <summary>
/// Return the parser back to the root of the message (even if the last segment was in a group) and add
/// the unexpected segment as a <see cref="IGroup.AddNonstandardSegment(string, int)"/>.
/// </summary>
DropToRoot,

/// <summary>
/// Throw an <see cref="HL7Exception"/>
/// </summary>
ThrowHl7Exception,
}
}
10 changes: 6 additions & 4 deletions src/NHapi.Base/Parser/XMLParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -389,10 +389,12 @@ public virtual void Parse(IType datatypeObject, XmlElement datatypeElement)
/// <summary> <p>Returns a minimal amount of data from a message string, including only the
/// data needed to send a response to the remote system. This includes the
/// following fields:
/// <ul><li>field separator</li>
/// <li>encoding characters</li>
/// <li>processing ID</li>
/// <li>message control ID</li></ul>
/// <list type="bullet">
/// <item><description>field separator</description></item>
/// <item><description>encoding characters</description></item>
/// <item><description>processing ID</description></item>
/// <item><description>message control ID</description></item>
/// </list>
/// This method is intended for use when there is an error parsing a message,
/// (so the Message object is unavailable) but an error message must be sent
/// back to the remote system including some of the information in the inbound
Expand Down
6 changes: 3 additions & 3 deletions src/NHapi.SourceGeneration/Generators/SegmentGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ public static void MakeAll(string baseDirectory, string version)
/// <summary>
/// Returns an alternate segment name to replace the given segment name.
/// Substitutions made include...
/// <ul>
/// <li>Replacing Z.. with Z</li>
/// </ul>
/// <list type="bullet">
/// <item><description>Replacing Z.. with Z</description></item>
/// </list>
/// </summary>
public static string AltSegName(string segmentName)
{
Expand Down
Loading