mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-27 21:55:54 +08:00
# Description Correct ownership, endpoint validation, policy propagation, subscription delivery, file handling and generated-model behavior across the stack, tools and samples. Add focused regression tests and update the corresponding guides and sample documentation. ### Previously included corrections - Require an active, matching session to generate or access transient ResultTransfer file handles. Cover both sessionless generation and reads against a handle owned by an active session, using live session owners in the Machinery tests. - Keep physical filesystem operations within their configured mount and apply the same confinement checks throughout file operations. - Validate LDS semaphore paths consistently during server registration and registration-store maintenance. ### Individual issues addressed | # | Component | Issue and correction | |---|---|---| | 1 | AI jobs and transfers | Jobs and transfers did not consistently retain their creator's identity and session. Apply ownership checks to descendants, file handles, subscriptions and execution, and recheck deployment permissions before dispatch. | | 2 | Password-management client | Password-bearing calls could use signing-only channels or follow a replacement connection. Capture an encrypted transport generation and keep dispatch bound to it; preserve ordinary non-password edits. | | 3 | GDS and certificate-push clients | Connections omitted hostname verification. Validate the original configured DNS name or IP address before session activation. | | 4 | Certificate push | Private-key uploads could use signing-only calls. Require an encrypted, generation-bound dispatch while preserving certificate-only updates and restoring the caller's identity afterward. | | 5 | MQTT client | The .NET Framework custom-trust callback could discard TLS hostname, certificate-availability and usage errors. Retain those checks while supporting configured issuer trust. | | 6 | DTLS handshake | Certificate trust was not tied to the configured peer address. Match the certificate's DNS or IP identity to the intended endpoint. | | 7 | Replicated address spaces | Serialized nodes lost per-node and descendant permission metadata. Preserve role permissions, user-role permissions and access restrictions, including updates to existing replica nodes. | | 8 | MCP PubSub imports | Imports without groups skipped checks on the effective broker destination. Check the actual endpoint before resolving credentials or activating the connection. | | 9 | Reference-server accounts | A disabled username account could authenticate again with its previous roles. Reject disabled accounts during fresh authentication. | | 10 | Console reference client | The sample disabled hostname checks when connecting to an otherwise trusted peer. Retain the original requested host and validate it before activation. | | 11 | Capture replay and export | Replay and raw export could accept non-capture files or include key material. Require complete PCAP/PCAPNG containers and exclude key sidecars and decryption-secret blocks. | | 12 | PubSub adapter fallback | The fallback client configuration automatically accepted peer certificates. Apply normal trust and hostname validation before activation or reads. | | 13 | Kafka transport | Explicit TLS enablement was checked but did not reach both final Confluent configurations. Use the same effective protocol for validation, producers and consumers. | | 14 | PubSub actions | Configuration rebuilds could widen a connection-local action handler's scope. Preserve its original connection association and reject mismatched dispatch. | | 15 | PubSub readers | Reader-level message-protection settings were accepted but ignored. Apply the effective group and reader settings before accepting and publishing received values. | | 16 | PubSub key groups | Different `SecurityGroupId` values could share one connection-wide key context. Reject mixed groups on a connection and require separate connections for distinct groups. | | 17 | MCP session registrations | Session-name replacement or reuse could retain another registration's credential bindings. Bind access to the registration, caller and authenticated endpoint, and preserve that identity when borrowing sessions. | | 18 | Viewer HTTP host | Requests reached the viewer's OPC UA session without consistent Host, Origin and port checks. Validate the request destination and browser origin before using the session, while retaining supported local MCP clients. | | 19 | Vision file operations | File operations did not consistently apply protected-file checks, and remote handles lacked caller and connection context. Apply the shared checks and use host-side opaque handles bound to caller, target and generation. | | 20 | DTLS record integrity | The integrity-only MAC used a truncated sequence number. Authenticate the full reconstructed sequence number and epoch so records remain distinct across rollover. | | 21 | AMB client sample | Connection setup omitted hostname validation. Preserve the originally requested host and verify the peer identity before activation. | | 22 | Robot sample writes | The R2 `SpeedOverride` callback could target R1 state. Bind each callback to its own robot and apply that robot's write policy. | | 23 | AI result properties | Optional result children inherited remotely writable defaults. Preserve their declaration restrictions and keep server-produced results read-only. | | 24 | WSS peer-trust updates | Existing channels did not consistently respond to peer-trust changes. Revalidate complete chains for forward and reverse WSS channels and close only those that no longer validate. | | 25 | GDS revocation checks | Caller-provided certificates could cause issuer retrieval from embedded URLs. Resolve validation from configured local trust, issuers and CRLs without fetching caller-provided locations. | | 26 | GMS observations | Published correction observations retained writable model defaults. Reject remote writes while preserving publisher-side updates. | | 27 | Production-dataset monitoring | Subscription admission and delivery could use the reporter's context instead of each subscriber's permissions. Evaluate the subscriber at admission and on every delivery, including cancellation and disposal paths. | | 28 | WoT MQTT destinations | Hostless MQTT forms could imply a localhost destination before loopback checks. Reject them before credential lookup or connection attempts and validate the effective endpoint. | | 29 | XRegistry opaque reads | Content-ID reads and notifications did not consistently honor encrypted-read requirements or the currently accepted transport. Recheck the bound endpoint and reject transport downgrades before rebinding, including when protected values are already queued. | | 30 | PubSub capture dissection | Key loading did not consistently check the configured capture-root boundary. Check each actual key path immediately before opening it. | | 31 | PubSub publication queues | Imported WriterGroup queues were not fully checked against publish-topic grants. Check the destination actually used by each group. | | 32 | MCP PubSub mutations | A caller-supplied mode could select subscribe grants for an operation that publishes. Derive the required direction and parent context from the actual mutation. | | 33 | Generated write masks | Model import and generation could widen an explicit `UserWriteMask`. Preserve it through import, copy, merge, inheritance and dependency metadata. | | 34 | Generated method flags | An explicit `UserExecutable=false` could be lost. Preserve its specified state and resulting method behavior through the same model paths. | | 35 | Generated role identifiers | Unresolved role identifiers could cause permission entries to be omitted. Preserve namespace-qualified role IDs and report a diagnostic when a policy cannot be represented. | | 36 | Aggregation-server defaults | The `localhost` default did not reliably constrain listener binding. Use numeric loopback for the default endpoint and command-line fallback. | | 37 | Certificate-validation cache | Cached results could skip current leaf or issuer validity checks. Recheck validity windows on cache hits and keep hostname validation independent of cached chain trust. | | 38 | Software-update folders | Revision names and marker contents containing dot segments could select paths outside the software root. Normalize and check every derived path against that root. | | 39 | USDA arrays | Array elements were not encoded for their string or asset context. Escape them as data and preserve valid composition and round-trip behavior. | | 40 | Adapter hot reload | A changed dataset definition with the same name could keep old fields, subscriptions or cached values active. Compare complete immutable definitions and retire old state before replacement. | | 41 | Adapter index ranges | Subscription publication could ignore `IndexRange` and return the complete value. Preserve the requested projection and its status and timestamps; reject unsupported range providers. | | 42 | PubSub metadata and targets | Metadata from one connection could change another connection's target mapping. Scope metadata to its connection and provenance, and resolve targets using actual typed field IDs rather than field names or unintended positional fallback. | | 43 | Scales product locks | Product locks were not applied across every remote mutation path. Apply them consistently to value writes, filling calculations and related recipe/controller operations while retaining permitted updates. | | 44 | Event permission caching | Cached event decisions could outlive identity, role or node-policy changes. Revalidate the current subscriber, event type and source permissions instead of reusing a stale decision. | | 45 | WoT Modbus destinations | Hostless Modbus forms could imply localhost before loopback checks. Reject them before connecting and validate the effective endpoint. | | 46 | MCP local PKI tools | Peer-trust mutations did not consistently require the caller's `CertificateAdministration` grant. Check the capability before trust and untrust operations. | | 47 | Robot-control HTTP bridge | The bridge lacked consistent Host, Origin and port validation and caller-specific session grants. Apply those checks before borrowing the OPC UA session and retain supported local clients. | | 48 | Subscription transfers | Transferred subscriptions could retain cached notifications after the destination's permissions changed. Require authorization continuity between source and destination identities and roles, invalidate stale retransmission data when continuity fails, and preserve retransmission behavior for compatible transfers. | ### Compatibility notes - Replication uses the versioned NSRP v1 policy envelope. Upgrade peers together and re-encode or reseed legacy topology from the authoritative model; missing permission metadata is not inferred from old records. - Integrity-only DTLS peers must be upgraded together for the full sequence/epoch MAC. AEAD behavior is unchanged. - Distinct PubSub key groups require separate connections. - Custom sessions that cannot capture the actual encrypted transport, and subscription providers that cannot honor a requested range, are rejected rather than silently changing the requested behavior. - Subscription transfers retain retransmission data only when the destination authorization remains compatible with the source snapshot; otherwise the old sequence numbers and cached data are invalidated. ## Related Issues No separate tracking issue is linked. The individual corrections are listed above. ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [ ] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received.
2542 lines
109 KiB
C#
2542 lines
109 KiB
C#
/* ========================================================================
|
|
* Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved.
|
|
*
|
|
* OPC Foundation MIT License 1.00
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use,
|
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following
|
|
* conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* The complete license agreement can be found here:
|
|
* http://opcfoundation.org/License/MIT/1.00/
|
|
* ======================================================================*/
|
|
|
|
namespace Opc.Ua.SourceGeneration
|
|
{
|
|
/// <summary>
|
|
/// Template strings
|
|
/// </summary>
|
|
internal static class NodeStateTemplates
|
|
{
|
|
/// <summary>
|
|
/// Main file template for predefined nodes code generation
|
|
/// </summary>
|
|
public static readonly TemplateString File = TemplateString.Parse(
|
|
$$"""
|
|
{{Tokens.CodeHeader}}
|
|
|
|
{{Tokens.ListOfImports}}
|
|
|
|
namespace {{Tokens.NamespacePrefix}}
|
|
{
|
|
{{Tokens.ListOfTypes}}
|
|
|
|
{{Tokens.ListOfTypeActivators}}
|
|
}
|
|
""");
|
|
|
|
/// <summary>
|
|
/// File template for the model's NodeSet import factory provider
|
|
/// </summary>
|
|
public static readonly TemplateString NodeSetImportSupport_File = TemplateString.Parse(
|
|
$$"""
|
|
{{Tokens.CodeHeader}}
|
|
|
|
#pragma warning disable RCS0056 // A generated identifier can make a line exceed 120 characters
|
|
|
|
namespace {{Tokens.NamespacePrefix}}
|
|
{
|
|
{{Tokens.ListOfTypes}}
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Main file template for predefined nodes code generation
|
|
/// </summary>
|
|
public static readonly TemplateString Extensions_File = TemplateString.Parse(
|
|
$$"""
|
|
{{Tokens.CodeHeader}}
|
|
|
|
{{Tokens.ListOfImports}}
|
|
|
|
namespace {{Tokens.NamespacePrefix}}
|
|
{
|
|
/// <summary>
|
|
/// Extensions that add functionality from the {{Tokens.NamespaceUri}} namespace.
|
|
/// </summary>
|
|
public static partial class {{Tokens.Namespace}}Extensions
|
|
{
|
|
/// <summary>
|
|
/// Creates and returns all node states for the {{Tokens.NamespaceUri}} namespace.
|
|
/// </summary>
|
|
/// <param name="nodes">The collection to add the node states to.</param>
|
|
/// <param name="context">The system context to use for initialization.</param>
|
|
/// <returns>Original collection with node states added.</returns>
|
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{Tokens.Tool}}", "{{Tokens.Version}}")]
|
|
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
|
|
public static global::Opc.Ua.NodeStateCollection Add{{Tokens.Namespace}}(
|
|
this global::Opc.Ua.NodeStateCollection nodes,
|
|
global::Opc.Ua.ISystemContext context)
|
|
{
|
|
{{Tokens.ListOfNodeStateInitializers}}
|
|
return nodes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds all nodestate activators of the {{Tokens.NamespaceUri}}
|
|
/// namespace to a INodeStateFactoryBuilder.
|
|
/// </summary>
|
|
/// <param name="builder">The node state factory builder.</param>
|
|
/// <returns>The builder passed as parameter for chaining.</returns>
|
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{Tokens.Tool}}", "{{Tokens.Version}}")]
|
|
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
|
|
public static global::Opc.Ua.INodeStateFactoryBuilder Add{{Tokens.Namespace}}(
|
|
this global::Opc.Ua.INodeStateFactoryBuilder builder)
|
|
{
|
|
{{Tokens.ListOfActivatorRegistrations}}
|
|
return builder;
|
|
}
|
|
|
|
{{Tokens.ListOfNodeStateInstanceFactories}}
|
|
|
|
{{Tokens.ListOfNodeStateTypeFactories}}
|
|
}
|
|
}
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Object Type node state
|
|
/// </summary>
|
|
public static readonly TemplateString ObjectType_Class = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// The {{Tokens.ClassName}} ObjectType state.
|
|
/// </summary>
|
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{Tokens.Tool}}", "{{Tokens.Version}}")]
|
|
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
|
|
public partial class {{Tokens.ClassName}}State :
|
|
{{Tokens.BaseClassName}}State{{Tokens.BaseT}}
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="{{Tokens.ClassName}}State"/> class.
|
|
/// </summary>
|
|
public {{Tokens.ClassName}}State(global::Opc.Ua.NodeState? parent)
|
|
: base(parent)
|
|
{
|
|
}
|
|
|
|
{{Tokens.ElementNamespaceOverride}}
|
|
|
|
{{Tokens.ListOfProperties}}
|
|
|
|
{{Tokens.ListOfNonMandatoryChildren}}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool DeepEquals(global::Opc.Ua.NodeState node)
|
|
{
|
|
if (!(node is {{Tokens.ClassName}}State state) || !base.DeepEquals(state))
|
|
{
|
|
return false;
|
|
}
|
|
{{Tokens.ListOfEqualityComparers}}
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int DeepGetHashCode()
|
|
{
|
|
int hashCode = base.DeepGetHashCode();
|
|
{{Tokens.ListOfChildHashes}}
|
|
return hashCode;
|
|
}
|
|
|
|
{{Tokens.ListOfChildOperations}}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void CopyTo(global::Opc.Ua.NodeState target)
|
|
{
|
|
if (!(target is {{Tokens.ClassName}}State state))
|
|
{
|
|
return;
|
|
}
|
|
{{Tokens.ListOfChildCopies}}
|
|
base.CopyTo(target);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.NodeState CreateCopy()
|
|
{
|
|
return new {{Tokens.ClassName}}State(null);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.NodeId GetDefaultTypeDefinitionId(
|
|
global::Opc.Ua.NamespaceTable namespaceUris)
|
|
{
|
|
return global::Opc.Ua.NodeId.Create(
|
|
global::{{Tokens.NamespacePrefix}}.ObjectTypes.{{Tokens.TypeName}},
|
|
{{Tokens.NamespaceUri}},
|
|
namespaceUris);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void Initialize(global::Opc.Ua.ISystemContext context)
|
|
{
|
|
base.Initialize(context);
|
|
Initialize(
|
|
context,
|
|
context.CreateInstanceOf{{Tokens.SymbolicId}}());
|
|
InitializeOptionalChildren(context);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void Initialize(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState source)
|
|
{
|
|
InitializeOptionalChildren(context);
|
|
base.Initialize(context, source);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void InitializeOptionalChildren(
|
|
global::Opc.Ua.ISystemContext context)
|
|
{
|
|
base.InitializeOptionalChildren(context);
|
|
{{Tokens.InitializeOptionalChildren}}
|
|
}
|
|
|
|
{{Tokens.ListOfFields}}
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Method type node state
|
|
/// </summary>
|
|
public static readonly TemplateString MethodType_Class = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// The {{Tokens.ClassName}} MethodType.
|
|
/// </summary>
|
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{Tokens.Tool}}", "{{Tokens.Version}}")]
|
|
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
|
|
public partial class {{Tokens.ClassName}} : global::Opc.Ua.MethodState
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="{{Tokens.ClassName}}"/> class.
|
|
/// </summary>
|
|
public {{Tokens.ClassName}}(global::Opc.Ua.NodeState? parent)
|
|
: base(parent)
|
|
{
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public new static global::Opc.Ua.NodeState Construct(global::Opc.Ua.NodeState parent)
|
|
{
|
|
return new {{Tokens.ClassName}}(parent);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public {{Tokens.ClassName}}MethodCallHandler? OnCall;
|
|
|
|
/// <inheritdoc/>
|
|
public {{Tokens.ClassName}}MethodAsyncCallHandler? OnCallAsync;
|
|
|
|
{{Tokens.ListOfProperties}}
|
|
|
|
{{Tokens.ListOfNonMandatoryChildren}}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool DeepEquals(global::Opc.Ua.NodeState node)
|
|
{
|
|
if (!(node is {{Tokens.ClassName}} state) || !base.DeepEquals(state))
|
|
{
|
|
return false;
|
|
}
|
|
{{Tokens.ListOfEqualityComparers}}
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int DeepGetHashCode()
|
|
{
|
|
int hashCode = base.DeepGetHashCode();
|
|
{{Tokens.ListOfChildHashes}}
|
|
return hashCode;
|
|
}
|
|
|
|
{{Tokens.ListOfChildOperations}}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void CopyTo(global::Opc.Ua.NodeState target)
|
|
{
|
|
if (!(target is {{Tokens.ClassName}} state))
|
|
{
|
|
return;
|
|
}
|
|
{{Tokens.ListOfChildCopies}}
|
|
base.CopyTo(target);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.NodeState CreateCopy()
|
|
{
|
|
return new {{Tokens.ClassName}}(null);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void Initialize(global::Opc.Ua.ISystemContext context)
|
|
{
|
|
base.Initialize(context);
|
|
Initialize(
|
|
context,
|
|
context.CreateInstanceOf{{Tokens.SymbolicId}}());
|
|
InitializeOptionalChildren(context);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void InitializeOptionalChildren(
|
|
global::Opc.Ua.ISystemContext context)
|
|
{
|
|
base.InitializeOptionalChildren(context);
|
|
{{Tokens.InitializeOptionalChildren}}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.ServiceResult? Call(
|
|
global::Opc.Ua.ISystemContext _context,
|
|
global::Opc.Ua.NodeId _objectId,
|
|
global::Opc.Ua.ArrayOf<global::Opc.Ua.Variant> _inputArguments,
|
|
global::System.Collections.Generic.List<global::Opc.Ua.Variant> _outputArguments)
|
|
{
|
|
if (OnCall == null)
|
|
{
|
|
return base.Call(_context, _objectId, _inputArguments, _outputArguments);
|
|
}
|
|
global::Opc.Ua.ServiceResult? _result = null;
|
|
{{Tokens.ListOfInputArguments}}
|
|
{{Tokens.ListOfOutputDeclarations}}
|
|
|
|
if (OnCall != null)
|
|
{
|
|
{{Tokens.OnCallImplementation}}
|
|
}
|
|
{{Tokens.ListOfOutputArguments}}
|
|
|
|
return _result;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override async
|
|
global::System.Threading.Tasks.ValueTask<global::Opc.Ua.ServiceResult?>
|
|
CallAsync(
|
|
global::Opc.Ua.ISystemContext _context,
|
|
global::Opc.Ua.NodeId _objectId,
|
|
global::Opc.Ua.ArrayOf<global::Opc.Ua.Variant> _inputArguments,
|
|
global::System.Collections.Generic.List<global::Opc.Ua.Variant> _outputArguments,
|
|
global::System.Threading.CancellationToken cancellationToken = default)
|
|
{
|
|
if (OnCall == null && OnCallAsync == null)
|
|
{
|
|
return await base.CallAsync(
|
|
_context,
|
|
_objectId,
|
|
_inputArguments,
|
|
_outputArguments,
|
|
cancellationToken).ConfigureAwait(false);
|
|
}
|
|
|
|
{{Tokens.ClassName}}Result? _result = null;
|
|
{{Tokens.ListOfInputArguments}}
|
|
|
|
if (OnCallAsync != null)
|
|
{
|
|
{{Tokens.OnCallAsyncImplementation}}
|
|
}
|
|
else if (OnCall != null)
|
|
{
|
|
return Call(_context, _objectId, _inputArguments, _outputArguments);
|
|
}
|
|
{{Tokens.ListOfOutputArgumentsFromResult}}
|
|
|
|
return _result?.ServiceResult;
|
|
}
|
|
|
|
{{Tokens.ListOfFields}}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents the result of a {{Tokens.ClassName}} method call.
|
|
/// </summary>
|
|
public partial class {{Tokens.ClassName}}Result
|
|
{
|
|
public global::Opc.Ua.ServiceResult ServiceResult { get; set; }
|
|
{{Tokens.ListOfResultProperties}}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the {{Tokens.ClassName}} method call.
|
|
/// </summary>
|
|
public delegate global::Opc.Ua.ServiceResult {{Tokens.ClassName}}MethodCallHandler(
|
|
{{Tokens.OnCallDeclaration}}
|
|
|
|
/// <summary>
|
|
/// Handles the asynchronous {{Tokens.ClassName}} method call.
|
|
/// </summary>
|
|
public delegate
|
|
global::System.Threading.Tasks.ValueTask<{{Tokens.ClassName}}Result>
|
|
{{Tokens.ClassName}}MethodAsyncCallHandler(
|
|
{{Tokens.OnCallAsyncDeclaration}}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Variable type node state
|
|
/// </summary>
|
|
public static readonly TemplateString VariableType_Class = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// The {{Tokens.ClassName}} VariableType state.
|
|
/// </summary>
|
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{Tokens.Tool}}", "{{Tokens.Version}}")]
|
|
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
|
|
public partial class {{Tokens.ClassName}}State :
|
|
{{Tokens.BaseClassName}}State{{Tokens.BaseT}}
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="{{Tokens.ClassName}}State"/> class.
|
|
/// </summary>
|
|
public {{Tokens.ClassName}}State(global::Opc.Ua.NodeState? parent) : base(parent)
|
|
{
|
|
}
|
|
|
|
{{Tokens.ListOfProperties}}
|
|
|
|
{{Tokens.ListOfNonMandatoryChildren}}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool DeepEquals(global::Opc.Ua.NodeState node)
|
|
{
|
|
if (!(node is {{Tokens.ClassName}}State state) || !base.DeepEquals(state))
|
|
{
|
|
return false;
|
|
}
|
|
{{Tokens.ListOfEqualityComparers}}
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int DeepGetHashCode()
|
|
{
|
|
int hashCode = base.DeepGetHashCode();
|
|
{{Tokens.ListOfChildHashes}}
|
|
return hashCode;
|
|
}
|
|
|
|
{{Tokens.ListOfChildOperations}}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void CopyTo(global::Opc.Ua.NodeState target)
|
|
{
|
|
if (!(target is {{Tokens.ClassName}}State state))
|
|
{
|
|
return;
|
|
}
|
|
{{Tokens.ListOfChildCopies}}
|
|
base.CopyTo(target);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.NodeState CreateCopy()
|
|
{
|
|
return new {{Tokens.ClassName}}State(null);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.NodeId GetDefaultTypeDefinitionId(
|
|
global::Opc.Ua.NamespaceTable namespaceUris)
|
|
{
|
|
return global::Opc.Ua.NodeId.Create(
|
|
global::{{Tokens.NamespacePrefix}}.VariableTypes.{{Tokens.TypeName}},
|
|
{{Tokens.NamespaceUri}},
|
|
namespaceUris);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.NodeId GetDefaultDataTypeId(
|
|
global::Opc.Ua.NamespaceTable namespaceUris)
|
|
{
|
|
return global::Opc.Ua.NodeId.Create(
|
|
global::{{Tokens.DataTypeNamespacePrefix}}.DataTypes.{{Tokens.DataType}},
|
|
{{Tokens.DataTypeNamespaceUri}},
|
|
namespaceUris);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override int GetDefaultValueRank()
|
|
{
|
|
return {{Tokens.ValueRank}};
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void Initialize(global::Opc.Ua.ISystemContext context)
|
|
{
|
|
base.Initialize(context);
|
|
Initialize(
|
|
context,
|
|
context.CreateInstanceOf{{Tokens.SymbolicId}}());
|
|
// InitializeOptionalChildren(context);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void Initialize(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState source)
|
|
{
|
|
InitializeOptionalChildren(context);
|
|
base.Initialize(context, source);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void InitializeOptionalChildren(
|
|
global::Opc.Ua.ISystemContext context)
|
|
{
|
|
base.InitializeOptionalChildren(context);
|
|
{{Tokens.InitializeOptionalChildren}}
|
|
}
|
|
|
|
{{Tokens.ListOfFields}}
|
|
}
|
|
|
|
{{Tokens.TypedVariableType}}
|
|
|
|
{{Tokens.VariableTypeValue}}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Factory methods for variable states with typed values
|
|
/// </summary>
|
|
public static readonly TemplateString FactoriesForVariableTypeWithTypedValue = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates a new instance of the {{Tokens.ClassName}}State class with a built-in value type
|
|
/// and associated TBuilder to extract the value from the Variant and create a new Variant
|
|
/// from it.
|
|
/// </summary>
|
|
public static {{Tokens.ClassName}}State<T> For<T, TBuilder>(global::Opc.Ua.NodeState? parent)
|
|
where TBuilder : struct, global::Opc.Ua.IVariantBuilder<T>
|
|
{
|
|
return new {{Tokens.ClassName}}State<T>.Implementation<TBuilder>(parent);
|
|
}
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Typed variable type node state
|
|
/// </summary>
|
|
public static readonly TemplateString VariableTypeWithTypedValue_Class = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// The {{Tokens.ClassName}} VariableType state.
|
|
/// </summary>
|
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{Tokens.Tool}}", "{{Tokens.Version}}")]
|
|
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
|
|
public abstract class {{Tokens.ClassName}}State<T> :
|
|
{{Tokens.ClassName}}State
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="{{Tokens.ClassName}}State{T}"/> class.
|
|
/// </summary>
|
|
protected {{Tokens.ClassName}}State(global::Opc.Ua.NodeState? parent)
|
|
: base(parent)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new instance of the <see cref="{{Tokens.ClassName}}State{T}"/>
|
|
/// class with a built-in value type and associated TBuilder to extract the
|
|
/// value from the Variant and create a new Variant from it.
|
|
/// </summary>
|
|
/// <typeparam name="TBuilder">The builder to use for T</typeparam>
|
|
public static {{Tokens.ClassName}}State<T> With<TBuilder>(
|
|
global::Opc.Ua.NodeState? parent = null)
|
|
where TBuilder : struct, global::Opc.Ua.IVariantBuilder<T>
|
|
{
|
|
return new Implementation<TBuilder>(parent);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public new abstract T Value { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
protected override void Initialize(global::Opc.Ua.ISystemContext context)
|
|
{
|
|
base.Initialize(context);
|
|
base.Initialize<T>(context);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void Initialize(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState source)
|
|
{
|
|
InitializeOptionalChildren(context);
|
|
base.Initialize(context, source);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds builder which extracts T from Variant or creates new Variant with type T
|
|
/// This is public so it can be overridden by classes outside of the namespace
|
|
/// </summary>
|
|
/// <typeparam name="TBuilder">The builder to use for T</typeparam>
|
|
public class Implementation<TBuilder> : {{Tokens.ClassName}}State<T>
|
|
where TBuilder : struct, global::Opc.Ua.IVariantBuilder<T>
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="{{Tokens.ClassName}}State{T}"/> class.
|
|
/// </summary>
|
|
public Implementation(global::Opc.Ua.NodeState? parent)
|
|
: base(parent)
|
|
{
|
|
m_builder = new TBuilder();
|
|
Value = default(T);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override T Value
|
|
{
|
|
get => m_builder.GetValue(WrappedValue);
|
|
set => WrappedValue = m_builder.WithValue(value);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.NodeState CreateCopy()
|
|
{
|
|
return new Implementation<TBuilder>(Parent);
|
|
}
|
|
|
|
private readonly TBuilder m_builder;
|
|
}
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Variable type value field methods
|
|
/// </summary>
|
|
public static readonly TemplateString VariableType_ValueMethods = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Handles the read of the {{Tokens.ChildName}} variable.
|
|
/// </summary>
|
|
private global::Opc.Ua.ServiceResult OnRead_{{Tokens.ChildName}}(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState node,
|
|
global::Opc.Ua.NumericRange indexRange,
|
|
global::Opc.Ua.QualifiedName dataEncoding,
|
|
ref global::Opc.Ua.Variant value,
|
|
ref global::Opc.Ua.StatusCode statusCode,
|
|
ref global::Opc.Ua.DateTimeUtc timestamp)
|
|
{
|
|
EnterLock();
|
|
try
|
|
{
|
|
DoBeforeReadProcessing(context, node);
|
|
|
|
var childVariable = m_variable?.{{Tokens.ChildPath}};
|
|
if (childVariable != null && global::Opc.Ua.StatusCode.IsBad(childVariable.StatusCode))
|
|
{
|
|
value = global::Opc.Ua.Variant.Null;
|
|
statusCode = childVariable.StatusCode;
|
|
return new global::Opc.Ua.ServiceResult(statusCode);
|
|
}
|
|
|
|
if (m_value != null)
|
|
{
|
|
value = global::Opc.Ua.Variant.{{Tokens.VariantFrom}}(
|
|
({{Tokens.ChildDataType}})m_value.{{Tokens.PropertyName}});
|
|
}
|
|
|
|
var result = Read(
|
|
context,
|
|
node,
|
|
indexRange,
|
|
dataEncoding,
|
|
ref value,
|
|
ref statusCode,
|
|
ref timestamp);
|
|
|
|
if (childVariable != null && global::Opc.Ua.ServiceResult.IsNotBad(result))
|
|
{
|
|
timestamp = childVariable.Timestamp;
|
|
if (statusCode != childVariable.StatusCode)
|
|
{
|
|
statusCode = childVariable.StatusCode;
|
|
result = new global::Opc.Ua.ServiceResult(statusCode);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
finally
|
|
{
|
|
ExitLock();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the write of the {{Tokens.ChildName}} variable.
|
|
/// </summary>
|
|
private global::Opc.Ua.ServiceResult OnWrite_{{Tokens.ChildName}}(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState node,
|
|
global::Opc.Ua.NumericRange indexRange,
|
|
global::Opc.Ua.QualifiedName dataEncoding,
|
|
ref global::Opc.Ua.Variant value,
|
|
ref global::Opc.Ua.StatusCode statusCode,
|
|
ref global::Opc.Ua.DateTimeUtc timestamp)
|
|
{
|
|
EnterLock();
|
|
try
|
|
{
|
|
if (!value.{{Tokens.VariantTryGet}}(out {{Tokens.ChildDataType}} newValue))
|
|
{
|
|
newValue = default;
|
|
}
|
|
UpdateChildVariableStatus(m_variable.{{Tokens.ChildPath}}, ref statusCode, ref timestamp);
|
|
m_value.{{Tokens.PropertyName}} = {{Tokens.ValueWrite}};
|
|
UpdateParent(context, ref statusCode, ref timestamp);
|
|
}
|
|
finally
|
|
{
|
|
ExitLock();
|
|
}
|
|
|
|
return global::Opc.Ua.ServiceResult.Good;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Variable type node state
|
|
/// </summary>
|
|
public static readonly TemplateString VariableTypeValue_Class = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// The {{Tokens.ClassName}} VariableType value.
|
|
/// </summary>
|
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{Tokens.Tool}}", "{{Tokens.Version}}")]
|
|
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
|
|
public class {{Tokens.ClassName}}Value : global::Opc.Ua.BaseVariableValue
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="{{Tokens.ClassName}}Value"/> class.
|
|
/// </summary>
|
|
public {{Tokens.ClassName}}Value(
|
|
{{Tokens.ClassName}}State variable,
|
|
{{Tokens.DataType}}? value,
|
|
global::System.Threading.Lock? dataLock)
|
|
: base(dataLock)
|
|
{
|
|
m_value = value;
|
|
|
|
if (m_value == null)
|
|
{
|
|
m_value = new {{Tokens.DataType}}();
|
|
}
|
|
|
|
Initialize(variable);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the variable associated with the value.
|
|
/// </summary>
|
|
public {{Tokens.ClassName}}State Variable => m_variable;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the value.
|
|
/// </summary>
|
|
public {{Tokens.DataType}} Value
|
|
{
|
|
get => m_value;
|
|
set => m_value = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes the value.
|
|
/// </summary>
|
|
private void Initialize({{Tokens.ClassName}}State variable)
|
|
{
|
|
EnterLock();
|
|
try
|
|
{
|
|
m_variable = variable;
|
|
|
|
variable.Value = m_value;
|
|
|
|
variable.OnReadValue = OnReadValue;
|
|
variable.OnWriteValue = OnWriteValue;
|
|
|
|
global::Opc.Ua.BaseVariableState? instance = null;
|
|
global::System.Collections.Generic.List<global::Opc.Ua.BaseInstanceState> updateList =
|
|
new global::System.Collections.Generic.List<global::Opc.Ua.BaseInstanceState>();
|
|
updateList.Add(variable);
|
|
|
|
{{Tokens.ListOfChildInitializers}}
|
|
|
|
SetUpdateList(updateList);
|
|
}
|
|
finally
|
|
{
|
|
ExitLock();
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected global::Opc.Ua.ServiceResult OnReadValue(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState node,
|
|
global::Opc.Ua.NumericRange indexRange,
|
|
global::Opc.Ua.QualifiedName dataEncoding,
|
|
ref global::Opc.Ua.Variant value,
|
|
ref global::Opc.Ua.StatusCode statusCode,
|
|
ref global::Opc.Ua.DateTimeUtc timestamp)
|
|
{
|
|
EnterLock();
|
|
try
|
|
{
|
|
DoBeforeReadProcessing(context, node);
|
|
|
|
if (m_value != null)
|
|
{
|
|
value = global::Opc.Ua.Variant.{{Tokens.VariantFrom}}(m_value);
|
|
}
|
|
|
|
return Read(context, node, indexRange, dataEncoding, ref value, ref statusCode, ref timestamp);
|
|
}
|
|
finally
|
|
{
|
|
ExitLock();
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
private global::Opc.Ua.ServiceResult OnWriteValue(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState node,
|
|
global::Opc.Ua.NumericRange indexRange,
|
|
global::Opc.Ua.QualifiedName dataEncoding,
|
|
ref global::Opc.Ua.Variant value,
|
|
ref global::Opc.Ua.StatusCode statusCode,
|
|
ref global::Opc.Ua.DateTimeUtc timestamp)
|
|
{
|
|
EnterLock();
|
|
try
|
|
{
|
|
if (!value.{{Tokens.VariantTryGet}}(out {{Tokens.DataType}} newValue))
|
|
{
|
|
newValue = default;
|
|
}
|
|
|
|
if ({{Tokens.ValueComparison}})
|
|
{
|
|
UpdateChildrenChangeMasks(context, ref newValue, ref statusCode, ref timestamp);
|
|
Timestamp = timestamp;
|
|
m_value = {{Tokens.ValueWrite}};
|
|
m_variable.UpdateChangeMasks(global::Opc.Ua.NodeStateChangeMasks.Value);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
ExitLock();
|
|
}
|
|
|
|
return global::Opc.Ua.ServiceResult.Good;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the change masks for the children.
|
|
/// </summary>
|
|
private void UpdateChildrenChangeMasks(
|
|
global::Opc.Ua.ISystemContext context,
|
|
ref {{Tokens.DataType}} newValue,
|
|
ref global::Opc.Ua.StatusCode statusCode,
|
|
ref global::Opc.Ua.DateTimeUtc timestamp)
|
|
{
|
|
{{Tokens.ListOfUpdateChildrenChangeMasks}}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the parent variable status.
|
|
/// </summary>
|
|
private void UpdateParent(
|
|
global::Opc.Ua.ISystemContext context,
|
|
ref global::Opc.Ua.StatusCode statusCode,
|
|
ref global::Opc.Ua.DateTimeUtc timestamp)
|
|
{
|
|
Timestamp = timestamp;
|
|
m_variable.UpdateChangeMasks(global::Opc.Ua.NodeStateChangeMasks.Value);
|
|
m_variable.ClearChangeMasks(context, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the status of a child variable.
|
|
/// </summary>
|
|
private void UpdateChildVariableStatus(
|
|
global::Opc.Ua.BaseVariableState child,
|
|
ref global::Opc.Ua.StatusCode statusCode,
|
|
ref global::Opc.Ua.DateTimeUtc timestamp)
|
|
{
|
|
if (child == null)
|
|
{
|
|
return;
|
|
}
|
|
child.StatusCode = statusCode;
|
|
if (timestamp == global::Opc.Ua.DateTimeUtc.MinValue)
|
|
{
|
|
timestamp = global::Opc.Ua.DateTimeUtc.Now;
|
|
}
|
|
child.Timestamp = timestamp;
|
|
}
|
|
|
|
{{Tokens.ListOfChildMethods}}
|
|
|
|
private {{Tokens.DataType}}? m_value;
|
|
private {{Tokens.ClassName}}State? m_variable;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Initialize optional child
|
|
/// </summary>
|
|
public static readonly TemplateString InitializeOptionalChild = TemplateString.Parse(
|
|
$$"""
|
|
if ({{Tokens.ChildName}} != null && global::Opc.Ua.NodeState.NeedsOptionalInitialization({{Tokens.ChildName}}))
|
|
{
|
|
{{Tokens.ChildName}}.Create(
|
|
context,
|
|
context.Create{{Tokens.SymbolicId}}(this, true));
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Property template
|
|
/// </summary>
|
|
public static readonly TemplateString Property = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// {{Tokens.ChildName}} property
|
|
/// </summary>
|
|
{{Tokens.AccessorSymbol}} {{Tokens.ClassName}}? {{Tokens.ChildName}}
|
|
{
|
|
get => {{Tokens.FieldName}};
|
|
set
|
|
{
|
|
if (!object.ReferenceEquals({{Tokens.FieldName}}, value))
|
|
{
|
|
ChangeMasks |= global::Opc.Ua.NodeStateChangeMasks.Children;
|
|
}
|
|
|
|
{{Tokens.FieldName}} = value;
|
|
}
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Override property template
|
|
/// </summary>
|
|
public static readonly TemplateString PropertyOverride = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// {{Tokens.ChildName}} property
|
|
/// </summary>
|
|
{{Tokens.AccessorSymbol}} {{Tokens.ClassName}}? {{Tokens.ChildName}}
|
|
{
|
|
get => ({{Tokens.ClassName}})base.{{Tokens.ChildName}};
|
|
set => base.{{Tokens.ChildName}} = value;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Add Optional component template
|
|
/// </summary>
|
|
public static readonly TemplateString OptionalMethod = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Adds the optional {{Tokens.ChildName}} child and returns this
|
|
/// instance so calls can be chained, e.g.
|
|
/// <c>parent.Add{{Tokens.ChildName}}(context).Add{{Tokens.ChildName}}Other(context)...</c>.
|
|
/// Idempotent: if {{Tokens.ChildName}} already exists the existing
|
|
/// child is kept and only its NodeId is overwritten (when a
|
|
/// non-null <paramref name="nodeId"/> is supplied).
|
|
/// </summary>
|
|
/// <param name="context">The system context.</param>
|
|
/// <param name="nodeId">
|
|
/// Optional NodeId for the newly-added child. When
|
|
/// <see cref="global::Opc.Ua.NodeId.Null"/> (the default), the
|
|
/// child keeps the type-level NodeId assigned by the generated
|
|
/// factory unless <paramref name="context"/>'s
|
|
/// <see cref="global::Opc.Ua.ISystemContext.NodeIdFactory"/> is
|
|
/// non-null, in which case a fresh NodeId is minted via the
|
|
/// factory.
|
|
/// </param>
|
|
{{Tokens.AccessorSymbol}} {{Tokens.OwnerClassName}} Add{{Tokens.ChildName}}(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeId nodeId = default)
|
|
{
|
|
if ({{Tokens.ChildName}} == null)
|
|
{
|
|
{{Tokens.ClassName}} state = context.Create{{Tokens.SymbolicId}}(this, true);
|
|
{{Tokens.ChildName}} = state;
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.NodeId previousNodeId = nodeState.NodeId;
|
|
if (!nodeId.IsNull)
|
|
{
|
|
nodeState.NodeId = nodeId;
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceChildNodeIds(
|
|
context,
|
|
state,
|
|
previousNodeId,
|
|
this);
|
|
}
|
|
else if (context.NodeIdFactory != null &&
|
|
nodeState.NodeId.Equals({{Tokens.NodeIdConstant}}))
|
|
{
|
|
previousNodeId =
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceNodeId(context, state);
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceChildNodeIds(
|
|
context,
|
|
state,
|
|
previousNodeId,
|
|
this);
|
|
}
|
|
}
|
|
else if (!nodeId.IsNull)
|
|
{
|
|
((global::Opc.Ua.NodeState){{Tokens.ChildName}}).NodeId = nodeId;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the optional {{Tokens.ChildName}} child and invokes
|
|
/// <paramref name="configure"/> on the (just-added or pre-existing)
|
|
/// typed child. Returns this instance for fluent chaining.
|
|
/// </summary>
|
|
/// <param name="context">The system context.</param>
|
|
/// <param name="configure">
|
|
/// Mutates the typed child in-place. Invoked after the child slot
|
|
/// is materialised so the callback can rely on the typed child
|
|
/// being non-null.
|
|
/// </param>
|
|
/// <param name="nodeId">
|
|
/// Optional NodeId for the newly-added child. See the
|
|
/// <see cref="Add{{Tokens.ChildName}}(global::Opc.Ua.ISystemContext, global::Opc.Ua.NodeId)"/>
|
|
/// overload for the default behaviour.
|
|
/// </param>
|
|
public {{Tokens.OwnerClassName}} Add{{Tokens.ChildName}}(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::System.Action<{{Tokens.ClassName}}> configure,
|
|
global::Opc.Ua.NodeId nodeId = default)
|
|
{
|
|
Add{{Tokens.ChildName}}(context, nodeId);
|
|
configure({{Tokens.ChildName}}!);
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Conditionally adds the optional {{Tokens.ChildName}} child
|
|
/// and invokes <paramref name="configure"/> on the typed child.
|
|
/// When <paramref name="condition"/> is <c>false</c> the child
|
|
/// is not materialised and the callback is not invoked.
|
|
/// Returns this instance for fluent chaining.
|
|
/// </summary>
|
|
/// <param name="context">The system context.</param>
|
|
/// <param name="condition">
|
|
/// Whether to add and configure the child. When <c>false</c>,
|
|
/// the call is a no-op.
|
|
/// </param>
|
|
/// <param name="configure">
|
|
/// Mutates the typed child in-place. Only invoked when
|
|
/// <paramref name="condition"/> is <c>true</c>.
|
|
/// </param>
|
|
/// <param name="nodeId">
|
|
/// Optional NodeId for the newly-added child.
|
|
/// </param>
|
|
public {{Tokens.OwnerClassName}} Add{{Tokens.ChildName}}(
|
|
global::Opc.Ua.ISystemContext context,
|
|
bool condition,
|
|
global::System.Action<{{Tokens.ClassName}}> configure,
|
|
global::Opc.Ua.NodeId nodeId = default)
|
|
{
|
|
if (!condition)
|
|
{
|
|
return this;
|
|
}
|
|
Add{{Tokens.ChildName}}(context, nodeId);
|
|
configure({{Tokens.ChildName}}!);
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the optional {{Tokens.ChildName}} child and invokes the
|
|
/// transform <paramref name="configure"/> on the typed child; the
|
|
/// callback's return value replaces the typed slot (so the
|
|
/// caller can wrap or substitute the child). Returns this
|
|
/// instance for fluent chaining.
|
|
/// </summary>
|
|
/// <param name="context">The system context.</param>
|
|
/// <param name="configure">
|
|
/// Transforms the typed child. The returned instance is stored
|
|
/// in the typed slot; pass back the same instance to keep it
|
|
/// unchanged or a new instance to replace it.
|
|
/// </param>
|
|
/// <param name="nodeId">
|
|
/// Optional NodeId for the newly-added child.
|
|
/// </param>
|
|
public {{Tokens.OwnerClassName}} Add{{Tokens.ChildName}}(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::System.Func<{{Tokens.ClassName}}, {{Tokens.ClassName}}> configure,
|
|
global::Opc.Ua.NodeId nodeId = default)
|
|
{
|
|
Add{{Tokens.ChildName}}(context, nodeId);
|
|
{{Tokens.ChildName}} = configure({{Tokens.ChildName}}!);
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Conditionally adds the optional {{Tokens.ChildName}} child and
|
|
/// invokes the transform <paramref name="configure"/> on the
|
|
/// typed child. When <paramref name="condition"/> is <c>false</c>
|
|
/// the child is not materialised and the callback is not invoked.
|
|
/// Returns this instance for fluent chaining.
|
|
/// </summary>
|
|
/// <param name="context">The system context.</param>
|
|
/// <param name="condition">
|
|
/// Whether to add and configure the child. When <c>false</c>,
|
|
/// the call is a no-op.
|
|
/// </param>
|
|
/// <param name="configure">
|
|
/// Transforms the typed child. Only invoked when
|
|
/// <paramref name="condition"/> is <c>true</c>.
|
|
/// </param>
|
|
/// <param name="nodeId">
|
|
/// Optional NodeId for the newly-added child.
|
|
/// </param>
|
|
public {{Tokens.OwnerClassName}} Add{{Tokens.ChildName}}(
|
|
global::Opc.Ua.ISystemContext context,
|
|
bool condition,
|
|
global::System.Func<{{Tokens.ClassName}}, {{Tokens.ClassName}}> configure,
|
|
global::Opc.Ua.NodeId nodeId = default)
|
|
{
|
|
if (!condition)
|
|
{
|
|
return this;
|
|
}
|
|
Add{{Tokens.ChildName}}(context, nodeId);
|
|
{{Tokens.ChildName}} = configure({{Tokens.ChildName}}!);
|
|
return this;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Place holder method template
|
|
/// </summary>
|
|
public static readonly TemplateString PlaceHolderMethod = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Add a placeholder {{Tokens.ChildName}} as child
|
|
/// </summary>
|
|
{{Tokens.AccessorSymbol}} {{Tokens.ClassName}} Add{{Tokens.ChildName}}(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.QualifiedName browseName)
|
|
{
|
|
{{Tokens.ClassName}} state =
|
|
context.Create{{Tokens.SymbolicId}}(this, browseName);
|
|
ReplaceChild(context, state);
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Find child methods
|
|
/// </summary>
|
|
public static readonly TemplateString ChildOperations = TemplateString.Parse(
|
|
$$"""
|
|
/// <inheritdoc/>
|
|
public override void GetChildren(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::System.Collections.Generic.IList<global::Opc.Ua.BaseInstanceState> children)
|
|
{
|
|
{{Tokens.ListOfFindChildren}}
|
|
|
|
base.GetChildren(context, children);
|
|
}
|
|
|
|
{{Tokens.ListOfCreateOrReplaceChild}}
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.BaseInstanceState? FindChild(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.QualifiedName browseName,
|
|
bool createOrReplace,
|
|
global::Opc.Ua.BaseInstanceState? replacement,
|
|
bool assignInstanceNodeIds = true)
|
|
{
|
|
global::Opc.Ua.BaseInstanceState? instance = null;
|
|
|
|
switch (browseName.Name)
|
|
{
|
|
{{Tokens.ListOfFindChildCase}}
|
|
}
|
|
|
|
if (instance != null)
|
|
{
|
|
return instance;
|
|
}
|
|
return base.FindChild(
|
|
context, browseName, createOrReplace, replacement, assignInstanceNodeIds);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void RemoveExplicitlyDefinedChild(global::Opc.Ua.BaseInstanceState child)
|
|
{
|
|
{{Tokens.ListOfRemoveChild}}
|
|
|
|
base.RemoveExplicitlyDefinedChild(child);
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Find child case template. Uses a literal string with the
|
|
/// runtime browse name (which may differ from the symbolic
|
|
/// name when the design overrides <c><opc:BrowseName></c>,
|
|
/// as in <c>Boiler.InputPipe</c> → <c>"PipeX001"</c>).
|
|
/// Avoids depending on <c>{Namespace}.BrowseNames.{ChildName}</c>
|
|
/// constants so cross-namespace inherited children compile
|
|
/// even when the foreign namespace's generated
|
|
/// <c>BrowseNames</c> class doesn't carry a constant for that
|
|
/// name.
|
|
/// </summary>
|
|
public static readonly TemplateString FindChildCase = TemplateString.Parse(
|
|
$$"""
|
|
case "{{Tokens.ChildBrowseNameLiteral}}":
|
|
{
|
|
instance = !createOrReplace ?
|
|
{{Tokens.ChildName}} : CreateOrReplace{{Tokens.ChildName}}(
|
|
context, replacement, assignInstanceNodeIds);
|
|
break;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Create or replace a child on the class. The optional
|
|
/// <c>assignInstanceNodeIds</c> parameter lets the generated type and
|
|
/// child factories opt out of per-instance NodeId assignment: they
|
|
/// build declaration subtrees whose NodeIds must stay at their
|
|
/// type-level values (the enclosing
|
|
/// <c>CreateInstanceOf<Type></c> factory rebases the finished
|
|
/// subtree in one pass). Every other caller - the generated
|
|
/// <c>FindChild</c> plumbing behind <c>NodeState.CreateChild</c> /
|
|
/// <c>NodeState.ReplaceChild</c> and hand-written node managers -
|
|
/// materialises children onto an already-instantiated tree and
|
|
/// therefore gets per-instance NodeIds by default.
|
|
/// </summary>
|
|
public static readonly TemplateString CreateOrReplaceChild = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Create or replace the mandatory {{Tokens.ChildName}} child
|
|
/// </summary>
|
|
/// <param name="context">The system context.</param>
|
|
/// <param name="replacement">
|
|
/// The child to adopt or to copy onto the existing child. When
|
|
/// <c>null</c> a new child is created.
|
|
/// </param>
|
|
/// <param name="assignInstanceNodeIds">
|
|
/// When <c>true</c> (the default) and the context supplies a
|
|
/// <see cref="global::Opc.Ua.ISystemContext.NodeIdFactory"/>, a
|
|
/// child that still carries a null or type-level NodeId - and its
|
|
/// descendants - are rebased onto per-instance NodeIds so multiple
|
|
/// instances of the same type never collide. A NodeId the caller
|
|
/// already assigned is never overwritten.
|
|
/// </param>
|
|
{{Tokens.AccessorSymbol}} {{Tokens.ClassName}} CreateOrReplace{{Tokens.ChildName}}(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.BaseInstanceState? replacement,
|
|
bool assignInstanceNodeIds = true)
|
|
{
|
|
if (replacement is {{Tokens.ClassName}} typedReplacement)
|
|
{
|
|
// a replacement of the matching type is used directly,
|
|
// replacing any child that may already exist.
|
|
{{Tokens.ChildName}} = typedReplacement;
|
|
}
|
|
else if ({{Tokens.ChildName}} == null)
|
|
{
|
|
{{Tokens.ClassName}} child = {{Tokens.ClassFactory}}(this);
|
|
// Stamp the child's identity so a path based NodeIdFactory
|
|
// can derive a per-instance NodeId for it below, and so
|
|
// NodeState.CreateChild returns a child that carries the
|
|
// browse name it was asked for.
|
|
global::Opc.Ua.NodeState childNode = child;
|
|
childNode.SymbolicName = "{{Tokens.BrowseNameLiteral}}";
|
|
childNode.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
"{{Tokens.ChildBrowseNameLiteral}}");
|
|
if (context.NamespaceUris != null)
|
|
{
|
|
childNode.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
"{{Tokens.ChildBrowseNameLiteral}}",
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
}
|
|
if (replacement != null)
|
|
{
|
|
child.Create(context, replacement);
|
|
}
|
|
{{Tokens.ChildName}} = child;
|
|
}
|
|
else if (replacement != null)
|
|
{
|
|
// an existing child is replaced by copying the replacement
|
|
// onto it, keeping the strongly typed instance.
|
|
{{Tokens.ChildName}}.Create(context, replacement);
|
|
}
|
|
if (assignInstanceNodeIds && context.NodeIdFactory != null)
|
|
{
|
|
global::Opc.Ua.NodeState childState = {{Tokens.ChildName}};
|
|
if (childState.NodeId.IsNull ||
|
|
childState.NodeId.Equals({{Tokens.NodeIdConstant}}))
|
|
{
|
|
global::Opc.Ua.NodeId previousNodeId =
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceNodeId(
|
|
context,
|
|
childState);
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceChildNodeIds(
|
|
context,
|
|
childState,
|
|
previousNodeId,
|
|
this);
|
|
}
|
|
}
|
|
return {{Tokens.ChildName}};
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Find children method template
|
|
/// </summary>
|
|
public static readonly TemplateString FindChildren = TemplateString.Parse(
|
|
$$"""
|
|
if ({{Tokens.FieldName}} != null)
|
|
{
|
|
children.Add({{Tokens.FieldName}});
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Remove child template
|
|
/// </summary>
|
|
public static readonly TemplateString RemoveChild = TemplateString.Parse(
|
|
$$"""
|
|
if (object.ReferenceEquals({{Tokens.FieldName}}, child))
|
|
{
|
|
{{Tokens.FieldName}} = null;
|
|
return;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Clone child template
|
|
/// </summary>
|
|
public static readonly TemplateString CloneChild = TemplateString.Parse(
|
|
$$"""
|
|
state.{{Tokens.BrowseName}} =
|
|
global::Opc.Ua.NodeState.CloneChild({{Tokens.BrowseName}}, state);
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Compare child template
|
|
/// </summary>
|
|
public static readonly TemplateString CompareChild = TemplateString.Parse(
|
|
$$"""
|
|
if (!global::Opc.Ua.NodeStateComparer.Default.Equals(
|
|
state.{{Tokens.BrowseName}},
|
|
{{Tokens.BrowseName}}))
|
|
{
|
|
return false;
|
|
}
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Hash child template
|
|
/// </summary>
|
|
public static readonly TemplateString HashChild = TemplateString.Parse(
|
|
$$"""
|
|
hashCode = (hashCode * 16777619) ^
|
|
global::Opc.Ua.NodeStateComparer.Default.GetHashCode({{Tokens.BrowseName}});
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Encodeable activator
|
|
/// </summary>
|
|
public static readonly TemplateString ActivatorClass = TemplateString.Parse(
|
|
$$"""
|
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{Tokens.Tool}}", "{{Tokens.Version}}")]
|
|
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
|
|
public sealed class {{Tokens.StateClassName}}Activator : global::Opc.Ua.NodeStateActivator
|
|
{
|
|
/// <summary>
|
|
/// The singleton instance of the activator.
|
|
/// </summary>
|
|
public static readonly {{Tokens.StateClassName}}Activator Instance
|
|
= new {{Tokens.StateClassName}}Activator();
|
|
|
|
/// <inheritdoc/>
|
|
protected override global::Opc.Ua.NodeState CreateInstance(
|
|
global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent)
|
|
{
|
|
return context.CreateInstanceOf{{Tokens.SymbolicId}}(parent);
|
|
}
|
|
}
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Nodestate activator registration
|
|
/// </summary>
|
|
public static readonly TemplateString ActivatorRegistration = TemplateString.Parse(
|
|
$$"""
|
|
// Register node state factory for {{Tokens.BrowseName}} {{Tokens.NodeClass}}
|
|
builder = builder.RegisterType(
|
|
{{Tokens.NodeClass}}Ids.{{Tokens.SymbolicId}},
|
|
{{Tokens.StateClassName}}Activator.Instance);
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for a single node state creation call
|
|
/// </summary>
|
|
public static readonly TemplateString Add = TemplateString.Parse(
|
|
$$"""
|
|
// Add {{Tokens.SymbolicName}} predefined node
|
|
{
|
|
global::Opc.Ua.NodeState state = Create{{Tokens.SymbolicId}}(context);
|
|
state.CreateAsPredefinedNode(context);
|
|
nodes.Add(state);
|
|
}
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for a single method state creation call.
|
|
/// </summary>
|
|
public static readonly TemplateString AddMethod = TemplateString.Parse(
|
|
$$"""
|
|
// Add {{Tokens.SymbolicName}} predefined node
|
|
{
|
|
global::Opc.Ua.NodeState state =
|
|
context.CreateInstanceOf{{Tokens.SymbolicId}}();
|
|
state.CreateAsPredefinedNode(context);
|
|
nodes.Add(state);
|
|
}
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for BaseObjectTypeState creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_ObjectType = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} ObjectType node state.
|
|
/// </summary>
|
|
internal static global::Opc.Ua.BaseObjectTypeState Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
bool forInstance = false)
|
|
{
|
|
var state = new global::Opc.Ua.BaseObjectTypeState();
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
state.SuperTypeId = {{Tokens.SuperTypeId}};
|
|
state.IsAbstract = {{Tokens.IsAbstract}};
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
nodeState.IsPartOfTypeHierarchy = true;
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for BaseDataVariableTypeState creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_VariableType = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} VariableType node state.
|
|
/// </summary>
|
|
internal static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
bool forInstance = false)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}();
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.BaseVariableTypeState baseState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.SuperTypeId = {{Tokens.SuperTypeId}};
|
|
baseState.IsAbstract = {{Tokens.IsAbstract}};
|
|
baseState.DataType = {{Tokens.DataTypeIdConstant}};
|
|
baseState.ValueRank = {{Tokens.ValueRank}};
|
|
{{Tokens.ArrayDimensions}}
|
|
{{Tokens.ValueCode}}
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
nodeState.IsPartOfTypeHierarchy = true;
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for ReferenceTypeState creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_ReferenceType = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} ReferenceType node state.
|
|
/// </summary>
|
|
internal static global::Opc.Ua.ReferenceTypeState Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
bool forInstance = false)
|
|
{
|
|
var state = new global::Opc.Ua.ReferenceTypeState();
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
state.SuperTypeId = {{Tokens.SuperTypeId}};
|
|
state.IsAbstract = {{Tokens.IsAbstract}};
|
|
state.Symmetric = {{Tokens.SymmetricValue}};
|
|
{{Tokens.InverseNameValue}}
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for DataTypeState creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_DataType = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} DataType node state.
|
|
/// </summary>
|
|
internal static global::Opc.Ua.DataTypeState Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
bool forInstance = false)
|
|
{
|
|
var state = new global::Opc.Ua.DataTypeState();
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
state.SuperTypeId = {{Tokens.SuperTypeId}};
|
|
state.IsAbstract = {{Tokens.IsAbstract}};
|
|
state.DataTypeDefinition = {{Tokens.DataTypeDefinition}};
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for BaseObjectState creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_Object = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} Object node state.
|
|
/// </summary>
|
|
internal static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
bool forInstance = true)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(null);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.BaseObjectState baseState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
baseState.NumericId = {{Tokens.NumericIdValue}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
// {{Tokens.ModellingRuleId}}
|
|
baseState.EventNotifier = {{Tokens.EventNotifier}};
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for BaseVariableState (Property or DataVariable) creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_Variable = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} Variable node state.
|
|
/// </summary>
|
|
internal static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
bool forInstance = true)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(null);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.BaseVariableState baseState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
baseState.NumericId = {{Tokens.NumericIdValue}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
// {{Tokens.ModellingRuleId}}
|
|
baseState.DataType = {{Tokens.DataTypeIdConstant}};
|
|
baseState.ValueRank = {{Tokens.ValueRank}};
|
|
{{Tokens.ArrayDimensions}}
|
|
baseState.AccessLevel = {{Tokens.AccessLevelValue}};
|
|
baseState.UserAccessLevel = {{Tokens.UserAccessLevelValue}};
|
|
baseState.MinimumSamplingInterval = {{Tokens.MinimumSamplingIntervalValue}};
|
|
baseState.Historizing = {{Tokens.HistorizingValue}};
|
|
{{Tokens.ValueCode}}
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for ViewState creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_View = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} View node state.
|
|
/// </summary>
|
|
internal static global::Opc.Ua.ViewState Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
bool forInstance = true)
|
|
{
|
|
var state = new global::Opc.Ua.ViewState();
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
state.EventNotifier = {{Tokens.EventNotifier}};
|
|
state.ContainsNoLoops = {{Tokens.ContainsNoLoopsValue}};
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for MethodState creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_InstanceOfMethodType = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates an instance of the {{Tokens.SymbolicName}} Method node state.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The returned node graph has not completed its create lifecycle.
|
|
/// Node manager registration completes it automatically. Call
|
|
/// <see cref="global::Opc.Ua.NodeState.CreateAsPredefinedNode(global::Opc.Ua.ISystemContext)"/>
|
|
/// before registration when configuration depends on
|
|
/// <c>OnBeforeCreate</c> or <c>OnAfterCreate</c>.
|
|
/// </remarks>
|
|
public static {{Tokens.StateClassName}} CreateInstanceOf{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent = null,
|
|
global::Opc.Ua.QualifiedName browseName = default)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(parent);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.MethodState baseState = state;
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
if (!browseName.IsNull)
|
|
{
|
|
nodeState.SymbolicName = browseName.Name;
|
|
nodeState.BrowseName = browseName;
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
|
|
}
|
|
else
|
|
{
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
}
|
|
{{Tokens.MethodDeclarationId}}
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
baseState.Executable = {{Tokens.ExecutableValue}};
|
|
baseState.UserExecutable = {{Tokens.UserExecutableValue}};
|
|
{{Tokens.ListOfInputArguments}}
|
|
{{Tokens.ListOfOutputArguments}}
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!browseName.IsNull && context.NodeIdFactory != null)
|
|
{
|
|
global::Opc.Ua.NodeId previousNodeId =
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceNodeId(context, state);
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceChildNodeIds(
|
|
context,
|
|
state,
|
|
previousNodeId);
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Creates a MethodState InputArguments or OutputArguments property.
|
|
/// </summary>
|
|
public static readonly TemplateString Create_MethodArguments = TemplateString.Parse(
|
|
$$"""
|
|
global::Opc.Ua.PropertyState<global::Opc.Ua.ArrayOf<global::Opc.Ua.Argument>> {{Tokens.PropertyName}} =
|
|
state.CreateOrReplace{{Tokens.BrowseName}}(context, null, assignInstanceNodeIds: false);
|
|
{{Tokens.PropertyName}}.SymbolicName = global::Opc.Ua.BrowseNames.{{Tokens.BrowseName}};
|
|
{{Tokens.PropertyName}}.BrowseName =
|
|
global::Opc.Ua.QualifiedName.From(global::Opc.Ua.BrowseNames.{{Tokens.BrowseName}});
|
|
{{Tokens.PropertyName}}.DisplayName =
|
|
new global::Opc.Ua.LocalizedText(global::Opc.Ua.BrowseNames.{{Tokens.BrowseName}});
|
|
{{Tokens.PropertyName}}.TypeDefinitionId = global::Opc.Ua.VariableTypeIds.PropertyType;
|
|
{{Tokens.PropertyName}}.ReferenceTypeId = global::Opc.Ua.ReferenceTypeIds.HasProperty;
|
|
{{Tokens.PropertyName}}.ModellingRuleId =
|
|
new global::Opc.Ua.NodeId(global::Opc.Ua.Objects.ModellingRule_Mandatory);
|
|
{{Tokens.PropertyName}}.DataType = global::Opc.Ua.DataTypeIds.Argument;
|
|
{{Tokens.PropertyName}}.ValueRank = global::Opc.Ua.ValueRanks.OneDimension;
|
|
{{Tokens.PropertyName}}.ArrayDimensions = global::Opc.Ua.ArrayOf.Wrapped(0u);
|
|
{{Tokens.PropertyName}}.Value = global::Opc.Ua.ArrayOf.ToArrayOf(
|
|
new global::Opc.Ua.Argument[]
|
|
{
|
|
{{Tokens.ListOfValues}}
|
|
});
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Overrides the value of an existing MethodState InputArguments or
|
|
/// OutputArguments property while leaving the identity of the property
|
|
/// node created by its own child factory untouched.
|
|
/// </summary>
|
|
public static readonly TemplateString Assign_MethodArgumentValues = TemplateString.Parse(
|
|
$$"""
|
|
global::Opc.Ua.PropertyState<global::Opc.Ua.ArrayOf<global::Opc.Ua.Argument>> {{Tokens.PropertyName}} =
|
|
state.CreateOrReplace{{Tokens.BrowseName}}(context, null, assignInstanceNodeIds: false);
|
|
{{Tokens.PropertyName}}.Value = global::Opc.Ua.ArrayOf.ToArrayOf(
|
|
new global::Opc.Ua.Argument[]
|
|
{
|
|
{{Tokens.ListOfValues}}
|
|
});
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for object type instance creation (instantiate an object type)
|
|
/// </summary>
|
|
public static readonly TemplateString Create_InstanceOfObjectType = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates an instance of the {{Tokens.TypeName}} type.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The returned node graph has not completed its create lifecycle.
|
|
/// Node manager registration completes it automatically. Call
|
|
/// <see cref="global::Opc.Ua.NodeState.CreateAsPredefinedNode(global::Opc.Ua.ISystemContext)"/>
|
|
/// before registration when configuration depends on
|
|
/// <c>OnBeforeCreate</c> or <c>OnAfterCreate</c>.
|
|
/// </remarks>
|
|
public static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent = null,
|
|
global::Opc.Ua.QualifiedName browseName = default)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(parent);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.BaseObjectState baseState = state;
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
if (!browseName.IsNull)
|
|
{
|
|
nodeState.SymbolicName = browseName.Name;
|
|
nodeState.BrowseName = browseName;
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
|
|
}
|
|
else
|
|
{
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
}
|
|
baseState.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
baseState.EventNotifier = {{Tokens.EventNotifier}};
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!browseName.IsNull && context.NodeIdFactory != null)
|
|
{
|
|
global::Opc.Ua.NodeId previousNodeId =
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceNodeId(context, state);
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceChildNodeIds(
|
|
context,
|
|
state,
|
|
previousNodeId);
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template variable type instance creation (instantiate a variable type)
|
|
/// </summary>
|
|
public static readonly TemplateString Create_InstanceOfVariableType = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates an instance of the {{Tokens.TypeName}} variable type.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The returned node graph has not completed its create lifecycle.
|
|
/// Node manager registration completes it automatically. Call
|
|
/// <see cref="global::Opc.Ua.NodeState.CreateAsPredefinedNode(global::Opc.Ua.ISystemContext)"/>
|
|
/// before registration when configuration depends on
|
|
/// <c>OnBeforeCreate</c> or <c>OnAfterCreate</c>.
|
|
/// </remarks>
|
|
public static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent = null,
|
|
global::Opc.Ua.QualifiedName browseName = default)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(parent);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.BaseVariableState baseState = state;
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
if (!browseName.IsNull)
|
|
{
|
|
nodeState.SymbolicName = browseName.Name;
|
|
nodeState.BrowseName = browseName;
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
|
|
}
|
|
else
|
|
{
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
}
|
|
|
|
baseState.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
{{Tokens.ModellingRuleId}}
|
|
baseState.DataType = {{Tokens.DataTypeIdConstant}};
|
|
baseState.ValueRank = {{Tokens.ValueRank}};
|
|
{{Tokens.ArrayDimensions}}
|
|
baseState.AccessLevel = {{Tokens.AccessLevelValue}};
|
|
baseState.UserAccessLevel = {{Tokens.UserAccessLevelValue}};
|
|
baseState.MinimumSamplingInterval = {{Tokens.MinimumSamplingIntervalValue}};
|
|
baseState.Historizing = {{Tokens.HistorizingValue}};
|
|
{{Tokens.ValueCode}}
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!browseName.IsNull && context.NodeIdFactory != null)
|
|
{
|
|
global::Opc.Ua.NodeId previousNodeId =
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceNodeId(context, state);
|
|
global::Opc.Ua.NodeInstanceExtensions.AssignInstanceChildNodeIds(
|
|
context,
|
|
state,
|
|
previousNodeId);
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for child object state creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_ChildObject = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates an instance of the {{Tokens.SymbolicName}} object node child component.
|
|
/// </summary>
|
|
internal static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent,
|
|
bool forInstance = false)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(parent);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.BaseObjectState baseState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
{{Tokens.InstanceNodeIdOverride}}
|
|
baseState.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
baseState.NumericId = {{Tokens.NumericIdValue}};
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
baseState.EventNotifier = {{Tokens.EventNotifier}};
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for child variable state creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_ChildVariable = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} child Variable node child component.
|
|
/// </summary>
|
|
internal static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent,
|
|
bool forInstance = false)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(parent);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.BaseVariableState baseState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
{{Tokens.InstanceNodeIdOverride}}
|
|
baseState.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
|
|
baseState.NumericId = {{Tokens.NumericIdValue}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
baseState.DataType = {{Tokens.DataTypeIdConstant}};
|
|
baseState.ValueRank = {{Tokens.ValueRank}};
|
|
{{Tokens.ArrayDimensions}}
|
|
baseState.AccessLevel = {{Tokens.AccessLevelValue}};
|
|
baseState.UserAccessLevel = {{Tokens.UserAccessLevelValue}};
|
|
baseState.MinimumSamplingInterval = {{Tokens.MinimumSamplingIntervalValue}};
|
|
baseState.Historizing = {{Tokens.HistorizingValue}};
|
|
{{Tokens.ValueCode}}
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
{{Tokens.MethodDeclarationId}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for child method state creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_ChildMethod = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} child Method node child component.
|
|
/// </summary>
|
|
internal static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent,
|
|
bool forInstance = false)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(parent);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.MethodState baseState = state;
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
{{Tokens.InstanceNodeIdOverride}}
|
|
{{Tokens.MethodDeclarationId}}
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
baseState.NumericId = {{Tokens.NumericIdValue}};
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
baseState.Executable = {{Tokens.ExecutableValue}};
|
|
baseState.UserExecutable = {{Tokens.UserExecutableValue}};
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
{{Tokens.ListOfInputArguments}}
|
|
{{Tokens.ListOfOutputArguments}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for child object state creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_ChildObject_Placeholder = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates an instance of the {{Tokens.SymbolicName}} object placeholder child.
|
|
/// </summary>
|
|
internal static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent,
|
|
global::Opc.Ua.QualifiedName browseName = default,
|
|
bool forInstance = false)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(parent);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.BaseObjectState baseState = state;
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
if (!browseName.IsNull)
|
|
{
|
|
nodeState.SymbolicName = browseName.Name;
|
|
nodeState.BrowseName = browseName;
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
|
|
forInstance = true;
|
|
}
|
|
else
|
|
{
|
|
// Create the state for the type parent
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
}
|
|
baseState.NumericId = {{Tokens.NumericIdValue}};
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
baseState.EventNotifier = {{Tokens.EventNotifier}};
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for child variable state creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_ChildVariable_Placeholder = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} child Variable object placeholder child.
|
|
/// </summary>
|
|
internal static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent,
|
|
global::Opc.Ua.QualifiedName browseName = default,
|
|
bool forInstance = false)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(parent);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.BaseVariableState baseState = state;
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
if (!browseName.IsNull)
|
|
{
|
|
nodeState.SymbolicName = browseName.Name;
|
|
nodeState.BrowseName = browseName;
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
|
|
forInstance = true;
|
|
}
|
|
else
|
|
{
|
|
// Create the state for the type parent
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
}
|
|
baseState.NumericId = {{Tokens.NumericIdValue}};
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
{{Tokens.ModellingRuleId}}
|
|
baseState.DataType = {{Tokens.DataTypeIdConstant}};
|
|
baseState.ValueRank = {{Tokens.ValueRank}};
|
|
{{Tokens.ArrayDimensions}}
|
|
baseState.AccessLevel = {{Tokens.AccessLevelValue}};
|
|
baseState.UserAccessLevel = {{Tokens.UserAccessLevelValue}};
|
|
baseState.MinimumSamplingInterval = {{Tokens.MinimumSamplingIntervalValue}};
|
|
baseState.Historizing = {{Tokens.HistorizingValue}};
|
|
{{Tokens.ValueCode}}
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for child method state creation
|
|
/// </summary>
|
|
public static readonly TemplateString Create_ChildMethod_Placeholder = TemplateString.Parse(
|
|
$$"""
|
|
/// <summary>
|
|
/// Creates the {{Tokens.SymbolicName}} child Method object placeholder child.
|
|
/// </summary>
|
|
internal static {{Tokens.StateClassName}} Create{{Tokens.SymbolicId}}(
|
|
this global::Opc.Ua.ISystemContext context,
|
|
global::Opc.Ua.NodeState parent,
|
|
global::Opc.Ua.QualifiedName browseName = default,
|
|
bool forInstance = false)
|
|
{
|
|
var state = {{Tokens.StateClassFactory}}(parent);
|
|
global::Opc.Ua.NodeState nodeState = state;
|
|
global::Opc.Ua.MethodState baseState = state;
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
if (!browseName.IsNull)
|
|
{
|
|
nodeState.SymbolicName = browseName.Name;
|
|
nodeState.BrowseName = browseName;
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
|
|
forInstance = true;
|
|
}
|
|
else
|
|
{
|
|
// Create the state for the type parent
|
|
nodeState.SymbolicName = {{Tokens.SymbolicNameSymbol}};
|
|
nodeState.BrowseName = new global::Opc.Ua.QualifiedName(
|
|
{{Tokens.BrowseNameSymbol}},
|
|
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
|
|
nodeState.DisplayName = new global::Opc.Ua.LocalizedText(
|
|
{{Tokens.DisplayName}});
|
|
}
|
|
baseState.NumericId = {{Tokens.NumericIdValue}};
|
|
{{Tokens.DescriptionValue}}
|
|
nodeState.WriteMask = {{Tokens.WriteMaskValue}};
|
|
nodeState.UserWriteMask = {{Tokens.UserWriteMaskValue}};
|
|
baseState.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
|
|
baseState.Executable = {{Tokens.ExecutableValue}};
|
|
baseState.UserExecutable = {{Tokens.UserExecutableValue}};
|
|
{{Tokens.MethodDeclarationId}}
|
|
{{Tokens.ReleaseStatusValue}}
|
|
{{Tokens.CategoriesValue}}
|
|
{{Tokens.SpecificationValue}}
|
|
{{Tokens.AccessRestrictionsValue}}
|
|
{{Tokens.ListOfRolePermissions}}
|
|
{{Tokens.ListOfReferences}}
|
|
{{Tokens.ListOfChildNodeStates}}
|
|
{{Tokens.ListOfInputArguments}}
|
|
{{Tokens.ListOfOutputArguments}}
|
|
if (!forInstance)
|
|
{
|
|
{{Tokens.ModellingRuleId}}
|
|
{{Tokens.ListOfOptionalChildNodeStates}}
|
|
}
|
|
return state;
|
|
}
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for role permissions collection initialization
|
|
/// </summary>
|
|
public static readonly TemplateString ListOfRolePermissions = TemplateString.Parse(
|
|
$$"""
|
|
nodeState.RolePermissions = new global::Opc.Ua.RolePermissionType[]
|
|
{
|
|
{{Tokens.ListOfRolePermissions}}
|
|
};
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Wrapper template for the singleton-instance NodeId override
|
|
/// emitted right after the type-level <c>nodeState.NodeId</c>
|
|
/// assignment in <c>Create_ChildObject</c> / <c>Create_ChildVariable</c>
|
|
/// / <c>Create_ChildMethod</c>. Renders only when at least one
|
|
/// singleton-instance branch is collected; otherwise the token
|
|
/// expands to nothing.
|
|
/// </summary>
|
|
public static readonly TemplateString InstanceNodeIdOverride = TemplateString.Parse(
|
|
$$"""
|
|
if (forInstance && parent != null)
|
|
{
|
|
{{Tokens.ListOfInstanceNodeIdBranches}}
|
|
}
|
|
""");
|
|
|
|
/// <summary>
|
|
/// One per-singleton branch of the singleton-instance
|
|
/// <c>nodeState.NodeId</c> override dispatch. Rebinds
|
|
/// <c>nodeState.NodeId</c> to <see cref="Tokens.NodeIdConstant"/>
|
|
/// when the parent owner matches <see cref="Tokens.ParentNodeIdConstant"/>.
|
|
/// </summary>
|
|
public static readonly TemplateString InstanceNodeIdBranch = TemplateString.Parse(
|
|
$$"""
|
|
{{Tokens.IfOrElseIf}} (parent.NodeId.Equals({{Tokens.ParentNodeIdConstant}}))
|
|
{
|
|
nodeState.NodeId = {{Tokens.NodeIdConstant}};
|
|
}
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for role permission
|
|
/// </summary>
|
|
public static readonly TemplateString RolePermission = TemplateString.Parse(
|
|
$$"""
|
|
new global::Opc.Ua.RolePermissionType
|
|
{
|
|
RoleId = {{Tokens.RoleIdConstant}},
|
|
Permissions = {{Tokens.PermissionsValue}}
|
|
},
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for description assignment
|
|
/// </summary>
|
|
public static readonly TemplateString Description = TemplateString.Parse(
|
|
$$"""
|
|
nodeState.Description = new global::Opc.Ua.LocalizedText({{Tokens.DescriptionValue}});
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for inverse name assignment
|
|
/// </summary>
|
|
public static readonly TemplateString InverseName = TemplateString.Parse(
|
|
$$"""
|
|
state.InverseName = new global::Opc.Ua.LocalizedText({{Tokens.InverseNameValue}});
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for release status assignment
|
|
/// </summary>
|
|
public static readonly TemplateString ReleaseStatus = TemplateString.Parse(
|
|
$$"""
|
|
nodeState.ReleaseStatus = {{Tokens.ReleaseStatusValue}};
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for categories assignment
|
|
/// </summary>
|
|
public static readonly TemplateString Categories = TemplateString.Parse(
|
|
$$"""
|
|
nodeState.Categories = {{Tokens.CategoriesValue}};
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for specification assignment
|
|
/// </summary>
|
|
public static readonly TemplateString Specification = TemplateString.Parse(
|
|
$$"""
|
|
nodeState.Specification = {{Tokens.SpecificationValue}};
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for access restrictions assignment
|
|
/// </summary>
|
|
public static readonly TemplateString AccessRestrictions = TemplateString.Parse(
|
|
$$"""
|
|
nodeState.AccessRestrictions = {{Tokens.AccessRestrictionsValue}};
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for method declaration id assignment
|
|
/// </summary>
|
|
public static readonly TemplateString MethodDeclarationId = TemplateString.Parse(
|
|
$$"""
|
|
baseState.MethodDeclarationId = {{Tokens.MethodDeclarationId}};
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for array dimensions assignment
|
|
/// </summary>
|
|
public static readonly TemplateString ArrayDimensions = TemplateString.Parse(
|
|
$$"""
|
|
baseState.ArrayDimensions = {{Tokens.ArrayDimensions}};
|
|
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for value assignment
|
|
/// </summary>
|
|
public static readonly TemplateString VariantArrayOfValue = TemplateString.Parse(
|
|
$$"""
|
|
baseState.WrappedValue = global::Opc.Ua.Variant.FromStructure(
|
|
global::Opc.Ua.ArrayOf.ToArrayOf(new {{Tokens.DataType}}[]
|
|
{
|
|
{{Tokens.ListOfValues}}
|
|
}));
|
|
""");
|
|
|
|
/// <summary>
|
|
/// Template for value assignment
|
|
/// </summary>
|
|
public static readonly TemplateString ArgumentValue = TemplateString.Parse(
|
|
$$"""
|
|
new global::Opc.Ua.Argument
|
|
{
|
|
Name = {{Tokens.Name}},
|
|
DataType = {{Tokens.DataType}},
|
|
ValueRank = {{Tokens.ValueRank}},
|
|
ArrayDimensions = {{Tokens.ArrayDimensions}},
|
|
Description = {{Tokens.Description}}
|
|
},
|
|
""");
|
|
}
|
|
}
|