Skip to content

Commit

Permalink
Some cleanup of the new APIs and Union implementation. (#2927)
Browse files Browse the repository at this point in the history
* Some cleanup of the new APIs and Union implementation.

* fix build

* Handle status code Uncertain according to the specification (#2898)

* #2896: Write output arguments for good and uncertain status code

When a method state's call method is invoked the output arguments should be written in case the status code is good or uncertain. This behavior would be conform with the current specification.

* #2896: The service result corresponds the method call result

The result of the Call method in the CustomNodeManager2 class represents the status of the CallMethodResult. It does not correspond to the ServiceResult of the CallResponse, thus returning Good as a general response is incorrect behavior.

* Add SetHiResClockDisabled  & fix Rejected Store Creation in ApplicationConfigurationBuilder (#2909)

Add the method SetHiResClockDisabled to IApplicationConfigurationBuilder
Fix the type of RejectedStore Created by the Builder to: CertificateStoreIdentifier

* revert based on feedback

* move some logic from class code to encoder/decoder

* Fix race condition on Nuget build (#2930)

- nodeset xmlzip is created in obj folders if multiple targets are built in parallel
  • Loading branch information
mregen authored Jan 17, 2025
1 parent 12c6504 commit 658fa77
Show file tree
Hide file tree
Showing 17 changed files with 841 additions and 805 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,7 @@ public override void Encode(IEncoder encoder)
{
encoder.PushNamespace(XmlNamespace);

if (encoder.UseReversibleEncoding)
{
encoder.WriteUInt32("EncodingMask", m_encodingMask);
}
encoder.WriteEncodingMask(m_encodingMask);

foreach (var property in GetPropertyEnumerator())
{
Expand All @@ -118,7 +115,22 @@ public override void Decode(IDecoder decoder)
{
decoder.PushNamespace(XmlNamespace);

m_encodingMask = decoder.ReadUInt32("EncodingMask");
m_encodingMask = decoder.ReadEncodingMask(null);

// try again if the mask is implicitly defined by the JSON keys
if (m_encodingMask == 0 && decoder is IJsonDecoder)
{
var masks = new StringCollection();
foreach (var property in GetPropertyEnumerator())
{
if (property.IsOptional)
{
masks.Add(property.Name);
}
}

m_encodingMask = decoder.ReadEncodingMask(masks);
}

foreach (var property in GetPropertyEnumerator())
{
Expand All @@ -132,6 +144,7 @@ public override void Decode(IDecoder decoder)

DecodeProperty(decoder, property);
}

decoder.PopNamespace();
}

Expand Down
80 changes: 28 additions & 52 deletions Libraries/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,9 @@ public override void Encode(IEncoder encoder)
{
encoder.PushNamespace(XmlNamespace);

string fieldName = null;

if (encoder.UseReversibleEncoding)
{
encoder.WriteUInt32("SwitchField", m_switchField);
fieldName = "Value";
}
// the encoder may return an override for the field name
// e.g. to support reversible JSON encoding
encoder.WriteSwitchField(m_switchField, out string fieldName);

if (m_switchField != 0)
{
Expand All @@ -116,16 +112,16 @@ public override void Encode(IEncoder encoder)
unionSelector++;
}

if (encoder is JsonEncoder je && (je.EncodingToUse == JsonEncodingType.Verbose || je.EncodingToUse == JsonEncodingType.Compact))
if (encoder.UseReversibleEncoding)
{
fieldName = unionProperty.Name;
fieldName = fieldName ?? unionProperty.Name;
}

EncodeProperty(encoder, fieldName, unionProperty);
}
else if (!encoder.UseReversibleEncoding)
{
encoder.WriteString(null, "null");
encoder.WriteString(null, null);

Check warning on line 124 in Libraries/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs

View check run for this annotation

Codecov / codecov/patch

Libraries/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs#L124

Added line #L124 was not covered by tests
}

encoder.PopNamespace();
Expand All @@ -139,63 +135,43 @@ public override void Decode(IDecoder decoder)
string fieldName = "Value";
UInt32 unionSelector = 0;

if (decoder is JsonDecoder jd)
{
object token = null;
m_switchField = 0;

if (jd.ReadField("SwitchField", out token))
{
m_switchField = decoder.ReadUInt32("SwitchField");
}

bool found = false;
unionSelector = decoder.ReadSwitchField(null);

// maybe the switch field is implicitly defined by the JSON keys
bool isJsonDecoder = decoder.EncodingType == EncodingType.Json;
if (unionSelector == 0 && isJsonDecoder)
{
var fields = new StringCollection();
foreach (var property in GetPropertyEnumerator())
{
unionSelector++;

if (jd.ReadField(property.Name, out token))
{
fieldName = property.Name;
m_switchField = unionSelector;
found = true;
break;
}

if (m_switchField == unionSelector)
if (property.IsOptional)
{
fieldName = property.Name;
break;
fields.Add(property.Name);

Check warning on line 149 in Libraries/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs

View check run for this annotation

Codecov / codecov/patch

Libraries/Opc.Ua.Client.ComplexTypes/Types/UnionComplexType.cs#L149

Added line #L149 was not covered by tests
}
}

if (!found)
{
if (jd.ReadField("Value", out token))
{
fieldName = "Value";
found = true;
}

if (!found)
{
unionSelector = 0;
}
}
}
else
{
unionSelector = m_switchField = decoder.ReadUInt32("SwitchField");
unionSelector = decoder.ReadSwitchField(fields);
}

m_switchField = unionSelector;
if (unionSelector > 0)
{
foreach (var property in GetPropertyEnumerator())
{
if (--unionSelector == 0)
{
DecodeProperty(decoder, fieldName, property);
fieldName = property.Name;

if (isJsonDecoder &&
decoder is IJsonDecoder jsonDecoder &&
jsonDecoder.ReadField("Value", out _))
{
DecodeProperty(jsonDecoder, "Value", property);
}
else
{
DecodeProperty(decoder, fieldName, property);
}
break;
}
}
Expand Down
4 changes: 0 additions & 4 deletions Libraries/Opc.Ua.Client/Opc.Ua.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@
<PackageId>$(PackageId).Debug</PackageId>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' != 'net6.0' AND '$(TargetFramework)' != 'net7.0' AND '$(TargetFramework)' != 'net8.0'">
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Stack\Opc.Ua.Core\Opc.Ua.Core.csproj" />
<ProjectReference Include="..\Opc.Ua.Configuration\Opc.Ua.Configuration.csproj" />
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ More samples based on the official [Nuget](https://www.nuget.org/packages/OPCFou
- **Thread Safety and Locking**: Improved thread safety and reduced locking in secure channel operations.
- **Audit and Redaction**: New interfaces for auditing and redacting sensitive information.

#### **New in 1.05.374 December release**
#### **New in 1.05.374 January release**
* Nodeset for Version 1.05.04
* Final version of JsonEncoder Compact and Verbose profiles

Expand Down
1 change: 0 additions & 1 deletion Stack/Opc.Ua.Core/Stack/Client/UserIdentity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ public string PolicyId
public string DisplayName
{
get { return m_displayName; }
set { m_displayName = value; }
}

/// <summary cref="IUserIdentity.TokenType" />
Expand Down
4 changes: 2 additions & 2 deletions Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1516,10 +1516,10 @@ public Array ReadArray(
}

/// <inheritdoc/>
public uint ReadSwitchField(Type switches) => ReadUInt32("SwitchField");
public uint ReadSwitchField(StringCollection switches) => ReadUInt32("SwitchField");

/// <inheritdoc/>
public uint ReadEncodingMask(Type masks) => ReadUInt32("EncodingMask");
public uint ReadEncodingMask(StringCollection masks) => ReadUInt32("EncodingMask");
#endregion

#region Private Methods
Expand Down
8 changes: 6 additions & 2 deletions Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2004,10 +2004,14 @@ public void WriteArray(string fieldName, object array, int valueRank, BuiltInTyp
}

/// <inheritdoc/>
public void WriteSwitchField(string fieldName, uint switchField) => WriteUInt32(fieldName, switchField);
public void WriteSwitchField(uint switchField, out string fieldName)
{
fieldName = null;
WriteUInt32("SwitchField", switchField);
}

/// <inheritdoc/>
public void WriteEncodingMask(string fieldName, uint encodingMask) => WriteUInt32(fieldName, encodingMask);
public void WriteEncodingMask(uint encodingMask) => WriteUInt32("EncodingMask", encodingMask);
#endregion

#region Private Methods
Expand Down
6 changes: 4 additions & 2 deletions Stack/Opc.Ua.Core/Types/Encoders/IDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,13 @@ Array ReadArray(
/// <summary>
/// Decode the switch field for a union.
/// </summary>
uint ReadSwitchField(Type switches);
/// <param name="switches">The list of field names in the order of the union selector.</param>
uint ReadSwitchField(StringCollection switches);

/// <summary>
/// Decode the encoding mask for a structure with optional fields.
/// </summary>
uint ReadEncodingMask(Type masks);
/// <param name="masks">The list of field names in the order of the bits in the optional fields mask.</param>
uint ReadEncodingMask(StringCollection masks);
}
}
22 changes: 12 additions & 10 deletions Stack/Opc.Ua.Core/Types/Encoders/IEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,12 @@ public interface IEncoder : IDisposable
void WriteByteString(string fieldName, ReadOnlySpan<byte> value);
#endif
/// <summary>
/// Writes an XmlElement to the stream.
/// Writes a XmlElement to the stream.
/// </summary>
void WriteXmlElement(string fieldName, XmlElement value);

/// <summary>
/// Writes an NodeId to the stream.
/// Writes a NodeId to the stream.
/// </summary>
void WriteNodeId(string fieldName, NodeId value);

Expand All @@ -180,32 +180,32 @@ public interface IEncoder : IDisposable
void WriteExpandedNodeId(string fieldName, ExpandedNodeId value);

/// <summary>
/// Writes an StatusCode to the stream.
/// Writes a StatusCode to the stream.
/// </summary>
void WriteStatusCode(string fieldName, StatusCode value);

/// <summary>
/// Writes an DiagnosticInfo to the stream.
/// Writes a DiagnosticInfo to the stream.
/// </summary>
void WriteDiagnosticInfo(string fieldName, DiagnosticInfo value);

/// <summary>
/// Writes an QualifiedName to the stream.
/// Writes a QualifiedName to the stream.
/// </summary>
void WriteQualifiedName(string fieldName, QualifiedName value);

/// <summary>
/// Writes an LocalizedText to the stream.
/// Writes a LocalizedText to the stream.
/// </summary>
void WriteLocalizedText(string fieldName, LocalizedText value);

/// <summary>
/// Writes an Variant array to the stream.
/// Writes a Variant array to the stream.
/// </summary>
void WriteVariant(string fieldName, Variant value);

/// <summary>
/// Writes an DataValue array to the stream.
/// Writes a DataValue array to the stream.
/// </summary>
void WriteDataValue(string fieldName, DataValue value);

Expand Down Expand Up @@ -372,12 +372,14 @@ public interface IEncoder : IDisposable
/// <summary>
/// Encode the switch field for a union.
/// </summary>
void WriteSwitchField(string fieldName, uint switchField);
/// <params name="switchField">The switch field </params>
/// <params name="alternateFieldName">Returns an alternate fieldName for the encoded union property if the encoder requires it, null otherwise.</params>
void WriteSwitchField(uint switchField, out string alternateFieldName);

/// <summary>
/// Encode the encoding mask for a structure with optional fields.
/// </summary>
void WriteEncodingMask(string fieldName, uint encodingMask);
void WriteEncodingMask(uint encodingMask);
}

/// <summary>
Expand Down
Loading

0 comments on commit 658fa77

Please sign in to comment.