v3 batch1 Wave-B contracts: byName-only resolver + RawTagEntry + green Core
- EquipmentTagRefResolver<TDef> re-keyed to RawPath: byName(RawPath)-only lookup, blob-parse fallback deleted (a miss is a miss). Clear() retained as documented no-op. - New RawTagEntry(RawPath, TagConfig, WriteIdempotent) in Core.Abstractions — the artifact->driver tag-delivery unit both WP5 (factory consumer) and WP4 (artifact producer) code against. - EquipmentNodeWalker greened for the dark Batch-1 address space: drop the raw-tag emission path (relied on removed Tag.EquipmentId/FullName); keep Area/Line/Equipment folders + VirtualTags + ScriptedAlarms. Raw-tag reference materialization is Batch 4. Commons, Core.Abstractions, Configuration, Core all build green.
This commit is contained in:
@@ -1,53 +1,60 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a driver subscription/read/write <c>fullReference</c> to a driver tag-definition,
|
||||
/// bridging the two authoring models: a legacy authored tag-table entry (looked up by name)
|
||||
/// OR an equipment tag whose reference is its raw <c>TagConfig</c> JSON (parsed on first use
|
||||
/// and cached). Negative results are cached too, so a genuinely-unknown reference is parsed once.
|
||||
/// v3: resolves a driver subscription/read/write reference — which is now always a
|
||||
/// <c>RawPath</c> — to the driver's internal tag-definition. The lookup is a single authored-table
|
||||
/// hit: each deploy hands the driver its authored raw tags keyed by RawPath (see
|
||||
/// <see cref="RawTagEntry"/>), the driver builds a <c>RawPath → TDef</c> table from them, and this
|
||||
/// resolver wraps that table's lookup. The pre-v3 blob-parse fallback (an equipment tag whose
|
||||
/// reference WAS its raw <c>TagConfig</c> JSON) is retired: a miss is a miss — <see cref="TryResolve"/>
|
||||
/// returns <see langword="false"/> and the driver surfaces Bad quality, never a parse attempt.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDef">The driver's internal tag-definition type.</typeparam>
|
||||
public sealed class EquipmentTagRefResolver<TDef> where TDef : class
|
||||
{
|
||||
private readonly Func<string, TDef?> _byName;
|
||||
private readonly Func<string, TDef?> _parseRef;
|
||||
private readonly ConcurrentDictionary<string, TDef?> _cache = new(StringComparer.Ordinal);
|
||||
private readonly Func<string, TDef?> _byRawPath;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="EquipmentTagRefResolver{TDef}"/> class.</summary>
|
||||
/// <param name="byName">Authored tag-table lookup (returns null on miss).</param>
|
||||
/// <param name="parseRef">Parses an equipment-tag reference (TagConfig JSON) into a transient def, or null.</param>
|
||||
public EquipmentTagRefResolver(Func<string, TDef?> byName, Func<string, TDef?> parseRef)
|
||||
/// <param name="byRawPath">The driver's authored-table lookup (RawPath → definition; null on miss).</param>
|
||||
public EquipmentTagRefResolver(Func<string, TDef?> byRawPath)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(byName);
|
||||
ArgumentNullException.ThrowIfNull(parseRef);
|
||||
_byName = byName;
|
||||
_parseRef = parseRef;
|
||||
ArgumentNullException.ThrowIfNull(byRawPath);
|
||||
_byRawPath = byRawPath;
|
||||
}
|
||||
|
||||
/// <summary>True when <paramref name="fullReference"/> resolves to a def (authored or equipment).</summary>
|
||||
/// <param name="fullReference">The wire reference handed to the driver.</param>
|
||||
/// <summary>True when <paramref name="rawPath"/> resolves to an authored tag-definition.</summary>
|
||||
/// <param name="rawPath">The RawPath wire reference handed to the driver.</param>
|
||||
/// <param name="def">
|
||||
/// The resolved tag-definition when this returns <see langword="true"/>. When this returns
|
||||
/// <see langword="false"/> the value is undefined — callers must not use it.
|
||||
/// <c>[MaybeNullWhen(false)]</c> informs the nullable-reference-types (NRT) analyser so
|
||||
/// callers in NRT-enabled contexts do not need to suppress warnings.
|
||||
/// </param>
|
||||
/// <returns><see langword="true"/> when a definition was found.</returns>
|
||||
public bool TryResolve(string fullReference, [MaybeNullWhen(false)] out TDef def)
|
||||
public bool TryResolve(string rawPath, [MaybeNullWhen(false)] out TDef def)
|
||||
{
|
||||
var authored = _byName(fullReference);
|
||||
if (authored is not null) { def = authored; return true; }
|
||||
|
||||
var resolved = _cache.GetOrAdd(fullReference, _parseRef);
|
||||
if (resolved is not null) { def = resolved; return true; }
|
||||
|
||||
def = default;
|
||||
return false;
|
||||
def = _byRawPath(rawPath);
|
||||
return def is not null;
|
||||
}
|
||||
|
||||
/// <summary>Drops the transient-parse cache (call on driver reinitialise so a config change re-parses).</summary>
|
||||
public void Clear() => _cache.Clear();
|
||||
/// <summary>
|
||||
/// No-op retained for call-site compatibility. v3 holds no transient parse cache — the driver
|
||||
/// rebuilds its authored <c>RawPath → TDef</c> table on reinitialise, and this resolver reads
|
||||
/// the driver's live table by closure, so there is nothing to clear here.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The unit of tag delivery from the deploy artifact to a driver: one authored raw
|
||||
/// <c>Tag</c>, identified by its <see cref="RawPath"/> (the v3 identity), carrying the
|
||||
/// driver-specific address blob (<see cref="TagConfig"/>) the driver dials and the platform flags
|
||||
/// the driver needs. A driver maps each entry to its typed definition (keyed by RawPath) via its
|
||||
/// own <c>TagConfig → definition</c> factory at table-build time.
|
||||
/// </summary>
|
||||
/// <param name="RawPath">The tag's cluster-scoped RawPath — the driver wire reference / identity.</param>
|
||||
/// <param name="TagConfig">The tag's schemaless driver-specific <c>TagConfig</c> JSON (the dialled address).</param>
|
||||
/// <param name="WriteIdempotent">Whether writes to this tag are safe to replay (R2 resilience contract).</param>
|
||||
public sealed record RawTagEntry(string RawPath, string TagConfig, bool WriteIdempotent);
|
||||
|
||||
Reference in New Issue
Block a user