Files
Marc Schier 94bc03b9f6 fix address space issues (#3705)
* fix missing mandatory children

* Source generator: fix encoding nodes, EventNotifier, and type RBAC

- Emit DataType encoding nodes (Default Binary/XML/JSON) into the
  generated address space. CollectEncodingNodes() discovers
  DataTypeEncodingType instances and builds synthetic hierarchies
  with their HasEncoding/HasDescription references.

- Auto-set EventNotifier=SubscribeToEvents on Object nodes that have
  forward HasEventSource or HasNotifier references. The fix works at
  two levels: ModelDesignValidator infers SupportsEvents on types with
  event references in design XML, and NodeStateGenerator checks the
  resolved reference set for merged instances that inherit references
  from their type definitions.

- Wrap AccessRestrictions/RolePermissions in if(forInstance) guards
  for ObjectType, VariableType, DataType, and ReferenceType templates
  so type definition nodes remain accessible to all users.

- Allow ModellingRule=None Object children on type definitions to be
  emitted (e.g. state machine states/transitions).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update missing nodes analysis after source generator fixes

Retest with admin credentials against ConsoleReferenceServer v1.05.07.
Categorize 794 truly missing nodes (after filtering optional/placeholder):
- 384 encoding nodes (NodeSet2.xml-only, not in design XML)
- 172 role instance children
- 84 other nodes
- Remaining: trust list, PubSub, diagnostics, etc.

RBAC and EventNotifier fixes confirmed working.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* update

* plans: detailed analysis of 292 remaining missing nodes

Replaced the two previous analysis files with a single consolidated
validation report. Each of the 292 nodes is classified with a reason:

- 212 type-level children (ObjectType definitions not instantiated)
- 48 instance-level children (diagnostics, HA, FileSystem, PubSub)
- 32 orphan property templates (design-time canonical definitions)

Only 1 fix recommended: Server.Auditing (i=2994) should be exposed
as false per Part 5 section 6.3.3.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add GDS node manager to ConsoleReferenceServer

Add Global Discovery Server functionality to the reference server:
- Add Opc.Ua.Gds.Server.Common project reference
- Add GdsNodeManagerFactory that creates ApplicationsNodeManager
  with JsonApplicationsDatabase and CertificateGroup (auto-approve)
- Add GlobalDiscoveryServerConfiguration extension to config XML
- Add GDS to ServerCapabilities
- Registration is opt-in: only when config extension is present

Also fix pre-existing source generator test failures:
- Add missing CreateOrReplaceTransitionNumber stub method to
  StateMachineTransitionState in CompilerUtils.cs (8 tests fixed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* plans: update missing nodes report with GDS retest results

Retested after adding GDS node manager to ConsoleReferenceServer.
Total missing reduced from 1325 to 1243 (82 fewer).
335 remaining 'other' nodes fully classified with per-node reasons.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* plans: Server.Auditing is present (access-restricted, not missing)

Live validation confirmed i=2994 exists with value=true, visible to
admin users. Returns BadUserAccessDenied for anonymous. No fixes needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix CttTestRunner build errors for v1.6 API and Jint 4.8.0

- Update System.CommandLine 2.0.7 API: SetHandler->SetAction, InvokeAsync->Parse().InvokeAsync()
- Remove ObjectInstance inheritance from CttAssert, CttServiceRegister, CttIdentifierConstants, CttMonitoredItemHelper; use ToJsObject() factory methods instead
- Replace Jint.Native.JsValueType with .IsObject()/.IsNumber()/.IsString() etc.
- Add missing using directives (Jint.Runtime, Microsoft.Extensions.Logging, etc.)
- Fix NodeId.Identifier obsolete -> TryGetIdentifier<uint>
- Fix DataValue.Value obsolete -> WrappedValue.AsBoxedObject()
- Fix ApplicationInstance() obsolete -> ApplicationInstance(ITelemetryContext)
- Fix LoadApplicationConfiguration -> LoadApplicationConfigurationAsync
- Fix CheckApplicationInstanceCertificate -> CheckApplicationInstanceCertificatesAsync
- Fix CoreClientUtils.SelectEndpointAsync signature (requires telemetry param)
- Fix DefaultSessionFactory() obsolete -> DefaultSessionFactory(ITelemetryContext)
- Fix DiscoveryClient.Create -> DiscoveryClient.CreateAsync
- Fix FindServers/GetEndpoints -> FindServersAsync/GetEndpointsAsync
- Fix StatusCode to uint conversions
- Fix ArrayOf<T> iteration (use foreach instead of LINQ on IConvertableToArray)
- Fix XmlNodeList null coalescing in CttProjectSettings
- Fix JsValue.False -> JsValue.FromObject(engine, false)
- Add --json option to Program.cs for machine-readable output

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: emit type-level children with ModellingRule=None for all node classes

The source generator's GetChildren method only included
ModellingRule=None children when they were ObjectDesign instances
(state machine states/transitions). This excluded Variables and
Methods that are explicitly defined on types without a modelling
rule, such as:

- ConditionType.ConditionRefresh (Method)
- ConditionType.ConditionRefresh2 (Method)
- ConditionType.SupportsFilteredRetain (Variable)
- ProgramStateMachineType.Creatable (Variable)
- Various TrueState/FalseState display-hint properties

Remove the ObjectDesign restriction so all explicitly defined
type-level children with ModellingRule=None are included in the
generated address space. This adds ~52 previously missing nodes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* plans: update report after ModellingRule=None generator fix

Type-level children dropped from 261 to 203 (-58) after fixing the
source generator to emit Variables and Methods with ModellingRule=None.
Total 'other' reduced from 335 to 283. No fixes needed for any
remaining nodes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* plans: all 203 type-level children confirmed present via Read

Verified all 203 'type-level children' exist in the server (none
return BadNodeIdUnknown). They return Good, BadUserAccessDenied,
or BadSecurityModeInsufficient -- all confirming the node exists
but is access-restricted for anonymous users.

All 1,316 export-missing nodes are now accounted for. Zero nodes
are actually missing from the server address space.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix CttTestRunner session service methods for CTT JS script compatibility

- Implement ServiceCreateSession with real Session.CreateAsync connection
- Implement ServiceActivateSession with proper response fields
- Implement ServiceCloseSession with session cleanup
- Fix UaSession constructor to provide service methods via CreateServiceObject
- Convert all type constructors from ClrFunction to JS functions for 'new' support
  (Jint 4.x ClrFunction does not support [[Construct]])
- Add UaChannel.connect/disconnect stubs for OpenSecureChannel flow
- Add UaDiscovery with getEndpoints/findServers from discovery session
- Add missing types: UaSubscriptionDiagnosticsDataType, UaHistoryUpdateResult, etc.
- Add missing enums: IdentifierType, Constants (DateTime/numeric limits)
- Add UaPkiCertificate.fromDER, UaByteString.fromStringData, PkiType, UaPkiUtility
- Add UaDateTime.Now constructor, equals/msecsTo methods
- Add UaStatusCode with isGood/isBad/isUncertain as JS constructor
- Fix response headers with Timestamp (UaDateTime), ServiceDiagnostics, StringTable
- Fix endpoint descriptions with Server, UserIdentityTokens, ServerCertificate
- Add CreateResponseHeader helper for consistent response header construction
- Override warnOnce.js loggers to avoid Function.caller incompatibility
- Add stopTest, checkResourceError (lowercase) global functions
- Add UaOpcServer constructor with all method stubs
- Handle JS parse errors in include() for malformed CTT files
- Test.Connect() now calls InstanciateHelpers with DiscoverySession

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add CttTestRunner: .NET replacement for CTT JavaScript host environment

Implements a Jint-based JavaScript engine that can execute the OPC Foundation's
Compliance Test Tool .js test scripts using the OPC UA .NET Standard stack.

Features:
- Parses CTT .ctt.xml project files (Qt AbstractItemModelData format)
- Loads and resolves CTT include() dependency chains (~100 library files)
- Registers ~250 Ua* type constructors for JavaScript
- Implements session.read/write/browse/getEndpoints/findServers
- Provides all OPC UA enumerations, NodeId constants, Assert methods
- CLI with --list, --file, --conformance-unit, --result, --json flags
- Headless operation for agent/CI integration

Current status: Framework connects to OPC UA server and loads CTT test
infrastructure. Session establishment flow needs additional property
compatibility for CreateSession/ActivateSession request objects.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: do not apply DefaultAccessRestrictions/DefaultRolePermissions to type definitions

ObjectType and VariableType nodes should never have access
restrictions or role permissions from DefaultAccessRestrictions/
DefaultRolePermissions. These defaults are meant to apply to
instances of the type, not to the type definition node itself.

Previously, CertificateGroupType, TrustListType, SecurityGroupType
and other types were incorrectly emitted with AccessRestrictions
inherited from their DefaultAccessRestrictions, making them
unreadable without encryption even though the spec defines no
restrictions on these type definitions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* CttTestRunner: fix session establishment flow

- Fix constructor patterns (new/no-new dual call support)
- Fix ResponseHeader with ServiceDiagnostics/StringTable
- Populate ServerNonce, ServerCertificate, ServerEndpoints in CreateSession response
- Add UaVariant setter methods (setNodeId/setString/setBoolean/etc.)
- Add UaCreateSessionRequest/ActivateSessionRequest with proper nested structures
- Fix UaPkiUtility/UaPkiCertificate with Thumbprint/toDERFile/loadCertificateFromFile
- Add missing enums: PerformUpdateType, SecurityPolicy, StructureType, etc.
- Add HostInfo, Bit helper, KeyPairCollection, ExpectedAndAcceptedResults
- Add _error.store(), MessageSecurityMode.toString()

Status: Session creates successfully, CreateSession validation runs,
hits validateCertificate in PKI chain (next to implement).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* plans: update report after DefaultAccessRestrictions type definition fix

ObjectTypes no longer have incorrect access restrictions. Type
children reduced from 203 to 164 (39 now visible). Total export-
missing reduced from 1316 to 1146. Remaining 164 type children are
individual methods/variables with spec-correct access restrictions.

Two source generator fixes applied:
- ModellingRule=None children for Variables/Methods
- DefaultAccessRestrictions not applied to ObjectType/VariableType

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* CttTestRunner: fix PKI, cert validation, warnOnce, session response

- Intercept warnOnce.js with Jint-compatible replacement (no Function.caller)
- Add _log.store() global helper
- Add HOSTNAMES/HostnameFromUrl helpers for cert hostname validation
- Add UaPkiCertificate properties: PublicKey, Issuer, Subject, KeyUsage, Hostnames
- Add UaPkiUtility.validateCertificate stub
- Add UaByteString static helpers: FromByteArray, ToByteArray, fromHexString
- Use JS UaNodeId constructor for proper equals() support
- Fill AuthenticationToken and 32-byte ServerNonce in CreateSession response
- Add clone/append to ByteString objects

Session flow: CreateSession validates, ActivateSession reached, hits
Channel.ServerCertificate.clone() (IsSecure check — next to fix).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* CttTestRunner: complete session establishment, crypto stubs, ByteString helpers

- Add _makeByteString() helper for consistent ByteString objects with clone/append/isEmpty
- Add UaCryptoProvider with asymmetricSign/Verify stubs
- Add UaExtensionObject setter methods (setAnonymousIdentityToken, etc.)
- Fix UaChannel with full properties (RequestedSecurityPolicyUri, IsSecure, etc.)
- Fix duplicate type registrations overriding custom constructors
- Fix ActivateSession response header with ServiceDiagnostics
- Remove UaCreateSessionResponse/ActivateSessionRequest/CloseSessionRequest duplicates

Status: Full session lifecycle works (GetEndpoints → OpenSecureChannel →
CreateSession → ActivateSession). Test scripts execute and hit server
capabilities initialization (MonitoredItem NodeId settings configuration).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* update

* plans: add spec references for access restriction reasoning

Added links to Part 3 sections 5.2.9, 5.2.11, and 6.3.3 explaining
why DefaultRolePermissions are applied to instance children but not
to type definitions. The NodeSet2.xml has no explicit RolePermissions
on these 164 nodes -- restrictions come from model design defaults.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: add GDS project references to ConsoleReferenceServer Dockerfile

Add Opc.Ua.Gds.Common and Opc.Ua.Gds.Server.Common csproj COPY
lines to the Docker restore layer, required since the GDS node
manager was added to the ConsoleReferenceServer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* update

* feat: add IsPartOfTypeHierarchy flag to bypass access restrictions on types

Type hierarchy nodes (ObjectType/VariableType definitions and their
children) should be universally accessible regardless of
AccessRestrictions and RolePermissions.

Changes:
- Add IsPartOfTypeHierarchy property to NodeState
- Set flag on ObjectType/VariableType in generated code (!forInstance)
- Propagate flag from parent to children in AddPredefinedNode
- Add flag to NodeMetadata, propagate in GetPermissionMetadata
- Bypass ValidateRolePermissions and ValidateAccessRestrictions
  when IsPartOfTypeHierarchy is true
- Revert isTypeDefinition guard: AccessRestrictions and
  RolePermissions are now emitted on all nodes as metadata,
  but enforcement is skipped for type hierarchy nodes
- Fix forInstance propagation in type factories: use
  forInstance: forInstance for type children so deep children
  (TrueState/FalseState etc.) are included when !forInstance

Type-level missing nodes reduced from 201 to 99. Remaining 99 are
in the server but not reachable by the export tool's browse path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* plans: update report with final IsPartOfTypeHierarchy results

Missing from export reduced to 998 (from 1325 original).
Type children: 201 -> 99 (forInstance propagation fix).
All nodes verified present via OPC UA Read.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: propagate IsPartOfTypeHierarchy in GetNodeMetadataAsync

The Browse service's per-reference ValidateRolePermissionsAsync
calls GetNodeMetadataAsync (not GetPermissionMetadataAsync). The
IsPartOfTypeHierarchy flag was only set in GetPermissionMetadataAsync,
causing type hierarchy nodes to be filtered out of Browse results.

This fixes 99 ObjectType children that were previously invisible
in Browse from their parent types. Type-level missing: 99 -> 0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* plans: final report -- 0 type-level children missing (694 total)

Type-level missing: 99 -> 0 after fixing IsPartOfTypeHierarchy
propagation in GetNodeMetadataAsync. Total export-missing: 694
(384 encoding + 236 access-restricted + 74 instance/orphan).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* update

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-28 14:20:37 +02:00

2099 lines
86 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>
/// 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.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(
{{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(
{{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(
{{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)
{
lock (Lock)
{
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.ChildPath}});
}
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;
}
}
/// <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)
{
lock (Lock)
{
if (!value.{{Tokens.VariantTryGet}}(out {{Tokens.ChildDataType}} newValue))
{
newValue = default;
}
UpdateChildVariableStatus(m_variable.{{Tokens.ChildPath}}, ref statusCode, ref timestamp);
m_value.{{Tokens.ChildPath}} = {{Tokens.ValueWrite}};
UpdateParent(context, ref statusCode, ref timestamp);
}
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,
object 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)
{
lock (Lock)
{
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);
}
}
/// <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)
{
lock (Lock)
{
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);
}
}
/// <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)
{
lock (Lock)
{
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);
}
}
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)
{
{{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>
/// Add an optional {{Tokens.ChildName}} child
/// </summary>
{{Tokens.AccessorSymbol}} {{Tokens.ClassName}} Add{{Tokens.ChildName}}(
global::Opc.Ua.ISystemContext context)
{
{{Tokens.ClassName}} state =
context.Create{{Tokens.SymbolicId}}(this, true);
{{Tokens.ChildName}} = state;
return state;
}
""");
/// <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)
{
if (browseName.IsNull)
{
return null;
}
global::Opc.Ua.BaseInstanceState? instance = null;
switch (browseName.Name)
{
{{Tokens.ListOfFindChildCase}}
}
if (instance != null)
{
return instance;
}
return base.FindChild(context, browseName, createOrReplace, replacement);
}
/// <inheritdoc/>
protected override void RemoveExplicitlyDefinedChild(global::Opc.Ua.BaseInstanceState child)
{
{{Tokens.ListOfRemoveChild}}
base.RemoveExplicitlyDefinedChild(child);
}
""");
/// <summary>
/// Find child case template
/// </summary>
public static readonly TemplateString FindChildCase = TemplateString.Parse(
$$"""
case {{Tokens.BrowseNameNamespacePrefix}}.BrowseNames.{{Tokens.ChildName}}:
{
instance = !createOrReplace ?
{{Tokens.ChildName}} : CreateOrReplace{{Tokens.ChildName}}(context, replacement);
break;
}
""");
/// <summary>
/// Create or replace a child on the class
/// </summary>
public static readonly TemplateString CreateOrReplaceChild = TemplateString.Parse(
$$"""
/// <summary>
/// Create or replace the mandatory {{Tokens.ChildName}} child
/// </summary>
{{Tokens.AccessorSymbol}} {{Tokens.ClassName}} CreateOrReplace{{Tokens.ChildName}}(
global::Opc.Ua.ISystemContext context,
global::Opc.Ua.BaseInstanceState replacement)
{
if ({{Tokens.ChildName}} == null)
{
{{Tokens.ClassName}}? child = replacement as {{Tokens.ClassName}};
if (child == null)
{
child = {{Tokens.ClassFactory}}(this);
if (replacement != null)
{
child.Create(context, replacement);
}
}
{{Tokens.ChildName}} = child;
}
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}} =
({{Tokens.ClassName}})global::Opc.Ua.CoreUtils.Clone({{Tokens.BrowseName}});
""");
/// <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 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();
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.SuperTypeId = {{Tokens.SuperTypeId}};
state.IsAbstract = {{Tokens.IsAbstract}};
{{Tokens.ReleaseStatusValue}}
{{Tokens.CategoriesValue}}
{{Tokens.SpecificationValue}}
if (forInstance)
{
{{Tokens.AccessRestrictionsValue}}
{{Tokens.ListOfRolePermissions}}
}
{{Tokens.ListOfReferences}}
{{Tokens.ListOfChildNodeStates}}
if (!forInstance)
{
state.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}}();
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.SuperTypeId = {{Tokens.SuperTypeId}};
state.IsAbstract = {{Tokens.IsAbstract}};
state.DataType = {{Tokens.DataTypeIdConstant}};
state.ValueRank = {{Tokens.ValueRank}};
{{Tokens.ArrayDimensions}}
{{Tokens.ValueCode}}
{{Tokens.ReleaseStatusValue}}
{{Tokens.CategoriesValue}}
{{Tokens.SpecificationValue}}
if (forInstance)
{
{{Tokens.AccessRestrictionsValue}}
{{Tokens.ListOfRolePermissions}}
}
{{Tokens.ListOfReferences}}
{{Tokens.ListOfChildNodeStates}}
if (!forInstance)
{
state.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();
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.SuperTypeId = {{Tokens.SuperTypeId}};
state.IsAbstract = {{Tokens.IsAbstract}};
state.Symmetric = {{Tokens.SymmetricValue}};
{{Tokens.InverseNameValue}}
{{Tokens.ReleaseStatusValue}}
{{Tokens.CategoriesValue}}
{{Tokens.SpecificationValue}}
if (forInstance)
{
{{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();
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.SuperTypeId = {{Tokens.SuperTypeId}};
state.IsAbstract = {{Tokens.IsAbstract}};
state.DataTypeDefinition = {{Tokens.DataTypeDefinition}};
{{Tokens.ReleaseStatusValue}}
{{Tokens.CategoriesValue}}
{{Tokens.SpecificationValue}}
if (forInstance)
{
{{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);
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
state.NumericId = {{Tokens.NumericIdValue}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
// {{Tokens.ModellingRuleId}}
state.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);
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
state.NumericId = {{Tokens.NumericIdValue}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
// {{Tokens.ModellingRuleId}}
state.DataType = {{Tokens.DataTypeIdConstant}};
state.ValueRank = {{Tokens.ValueRank}};
{{Tokens.ArrayDimensions}}
state.AccessLevel = {{Tokens.AccessLevelValue}};
state.UserAccessLevel = {{Tokens.UserAccessLevelValue}};
state.MinimumSamplingInterval = {{Tokens.MinimumSamplingIntervalValue}};
state.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)
{
var state = new global::Opc.Ua.ViewState();
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText({{Tokens.DisplayName}});
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.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>
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);
state.NodeId = {{Tokens.NodeIdConstant}};
if (!browseName.IsNull)
{
state.SymbolicName = browseName.Name;
state.BrowseName = browseName;
state.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
}
else
{
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
}
{{Tokens.MethodDeclarationId}}
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
state.Executable = {{Tokens.ExecutableValue}};
state.UserExecutable = {{Tokens.ExecutableValue}};
{{Tokens.ListOfInputArguments}}
{{Tokens.ListOfOutputArguments}}
{{Tokens.ReleaseStatusValue}}
{{Tokens.CategoriesValue}}
{{Tokens.SpecificationValue}}
{{Tokens.AccessRestrictionsValue}}
{{Tokens.ListOfRolePermissions}}
{{Tokens.ListOfReferences}}
{{Tokens.ListOfChildNodeStates}}
return state;
}
""");
/// <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>
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);
state.NodeId = {{Tokens.NodeIdConstant}};
if (!browseName.IsNull)
{
state.SymbolicName = browseName.Name;
state.BrowseName = browseName;
state.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
}
else
{
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
}
state.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
state.EventNotifier = {{Tokens.EventNotifier}};
{{Tokens.ReleaseStatusValue}}
{{Tokens.CategoriesValue}}
{{Tokens.SpecificationValue}}
{{Tokens.AccessRestrictionsValue}}
{{Tokens.ListOfRolePermissions}}
{{Tokens.ListOfReferences}}
{{Tokens.ListOfChildNodeStates}}
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>
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);
state.NodeId = {{Tokens.NodeIdConstant}};
if (!browseName.IsNull)
{
state.SymbolicName = browseName.Name;
state.BrowseName = browseName;
state.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
}
else
{
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
}
state.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
{{Tokens.ModellingRuleId}}
state.DataType = {{Tokens.DataTypeIdConstant}};
state.ValueRank = {{Tokens.ValueRank}};
{{Tokens.ArrayDimensions}}
state.AccessLevel = {{Tokens.AccessLevelValue}};
state.UserAccessLevel = {{Tokens.UserAccessLevelValue}};
state.MinimumSamplingInterval = {{Tokens.MinimumSamplingIntervalValue}};
state.Historizing = {{Tokens.HistorizingValue}};
{{Tokens.ValueCode}}
{{Tokens.ReleaseStatusValue}}
{{Tokens.CategoriesValue}}
{{Tokens.SpecificationValue}}
{{Tokens.AccessRestrictionsValue}}
{{Tokens.ListOfRolePermissions}}
{{Tokens.ListOfReferences}}
{{Tokens.ListOfChildNodeStates}}
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);
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
state.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
state.NumericId = {{Tokens.NumericIdValue}};
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
state.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);
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
state.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
state.NumericId = {{Tokens.NumericIdValue}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
state.DataType = {{Tokens.DataTypeIdConstant}};
state.ValueRank = {{Tokens.ValueRank}};
{{Tokens.ArrayDimensions}}
state.AccessLevel = {{Tokens.AccessLevelValue}};
state.UserAccessLevel = {{Tokens.UserAccessLevelValue}};
state.MinimumSamplingInterval = {{Tokens.MinimumSamplingIntervalValue}};
state.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);
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.NodeId = {{Tokens.NodeIdConstant}};
{{Tokens.MethodDeclarationId}}
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
state.NumericId = {{Tokens.NumericIdValue}};
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
state.Executable = {{Tokens.ExecutableValue}};
state.UserExecutable = {{Tokens.ExecutableValue}};
{{Tokens.ReleaseStatusValue}}
{{Tokens.CategoriesValue}}
{{Tokens.SpecificationValue}}
if (forInstance)
{
{{Tokens.AccessRestrictionsValue}}
{{Tokens.ListOfRolePermissions}}
}
{{Tokens.ListOfReferences}}
{{Tokens.ListOfChildNodeStates}}
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);
state.NodeId = {{Tokens.NodeIdConstant}};
if (!browseName.IsNull)
{
state.SymbolicName = browseName.Name;
state.BrowseName = browseName;
state.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
forInstance = true;
}
else
{
// Create the state for the type parent
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
}
state.NumericId = {{Tokens.NumericIdValue}};
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
state.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);
state.NodeId = {{Tokens.NodeIdConstant}};
if (!browseName.IsNull)
{
state.SymbolicName = browseName.Name;
state.BrowseName = browseName;
state.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
forInstance = true;
}
else
{
// Create the state for the type parent
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
}
state.NumericId = {{Tokens.NumericIdValue}};
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.TypeDefinitionId = {{Tokens.TypeDefinitionId}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
{{Tokens.ModellingRuleId}}
state.DataType = {{Tokens.DataTypeIdConstant}};
state.ValueRank = {{Tokens.ValueRank}};
{{Tokens.ArrayDimensions}}
state.AccessLevel = {{Tokens.AccessLevelValue}};
state.UserAccessLevel = {{Tokens.UserAccessLevelValue}};
state.MinimumSamplingInterval = {{Tokens.MinimumSamplingIntervalValue}};
state.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);
state.NodeId = {{Tokens.NodeIdConstant}};
if (!browseName.IsNull)
{
state.SymbolicName = browseName.Name;
state.BrowseName = browseName;
state.DisplayName = new global::Opc.Ua.LocalizedText(browseName.Name);
forInstance = true;
}
else
{
// Create the state for the type parent
state.SymbolicName = {{Tokens.SymbolicNameSymbol}};
state.BrowseName = new global::Opc.Ua.QualifiedName(
{{Tokens.BrowseNameSymbol}},
context.NamespaceUris.GetIndexOrAppend({{Tokens.BrowseNameNamespaceUri}}));
state.DisplayName = new global::Opc.Ua.LocalizedText(
{{Tokens.DisplayName}});
}
state.NumericId = {{Tokens.NumericIdValue}};
{{Tokens.DescriptionValue}}
state.WriteMask = {{Tokens.WriteMaskValue}};
state.UserWriteMask = {{Tokens.UserWriteMaskValue}};
state.ReferenceTypeId = {{Tokens.ReferenceTypeId}};
state.Executable = {{Tokens.ExecutableValue}};
state.UserExecutable = {{Tokens.ExecutableValue}};
{{Tokens.MethodDeclarationId}}
{{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 role permissions collection initialization
/// </summary>
public static readonly TemplateString ListOfRolePermissions = TemplateString.Parse(
$$"""
state.RolePermissions = new global::Opc.Ua.RolePermissionType[]
{
{{Tokens.ListOfRolePermissions}}
};
""");
/// <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(
$$"""
state.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(
$$"""
state.ReleaseStatus = {{Tokens.ReleaseStatusValue}};
""");
/// <summary>
/// Template for categories assignment
/// </summary>
public static readonly TemplateString Categories = TemplateString.Parse(
$$"""
state.Categories = {{Tokens.CategoriesValue}};
""");
/// <summary>
/// Template for specification assignment
/// </summary>
public static readonly TemplateString Specification = TemplateString.Parse(
$$"""
state.Specification = {{Tokens.SpecificationValue}};
""");
/// <summary>
/// Template for access restrictions assignment
/// </summary>
public static readonly TemplateString AccessRestrictions = TemplateString.Parse(
$$"""
state.AccessRestrictions = {{Tokens.AccessRestrictionsValue}};
""");
/// <summary>
/// Template for method declaration id assignment
/// </summary>
public static readonly TemplateString MethodDeclarationId = TemplateString.Parse(
$$"""
state.MethodDeclarationId = {{Tokens.MethodDeclarationId}};
""");
/// <summary>
/// Template for array dimensions assignment
/// </summary>
public static readonly TemplateString ArrayDimensions = TemplateString.Parse(
$$"""
state.ArrayDimensions = {{Tokens.ArrayDimensions}};
""");
/// <summary>
/// Template for value assignment
/// </summary>
public static readonly TemplateString VariantArrayOfValue = TemplateString.Parse(
$$"""
state.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}}
},
""");
}
}