diff --git a/milo-examples/client-examples/src/main/java/org/eclipse/milo/examples/client/ClientExampleRunner.java b/milo-examples/client-examples/src/main/java/org/eclipse/milo/examples/client/ClientExampleRunner.java index 1e0fca3aa..6cc3e6c14 100644 --- a/milo-examples/client-examples/src/main/java/org/eclipse/milo/examples/client/ClientExampleRunner.java +++ b/milo-examples/client-examples/src/main/java/org/eclipse/milo/examples/client/ClientExampleRunner.java @@ -22,15 +22,13 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.eclipse.milo.examples.server.ExampleServer; import org.eclipse.milo.opcua.sdk.client.OpcUaClient; -import org.eclipse.milo.opcua.stack.client.security.DefaultClientCertificateValidator; import org.eclipse.milo.opcua.stack.core.Stack; +import org.eclipse.milo.opcua.stack.core.security.DefaultClientCertificateValidator; import org.eclipse.milo.opcua.stack.core.security.DefaultTrustListManager; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - public class ClientExampleRunner { static { @@ -90,8 +88,9 @@ private OpcUaClient createClient() throws Exception { endpoints.stream() .filter(clientExample.endpointFilter()) .findFirst(), - configBuilder -> - configBuilder + transportConfigBuilder -> {}, + clientConfigBuilder -> + clientConfigBuilder .setApplicationName(LocalizedText.english("eclipse milo opc-ua client")) .setApplicationUri("urn:eclipse:milo:examples:client") .setKeyPair(loader.getClientKeyPair()) @@ -99,8 +98,6 @@ private OpcUaClient createClient() throws Exception { .setCertificateChain(loader.getClientCertificateChain()) .setCertificateValidator(certificateValidator) .setIdentityProvider(clientExample.getIdentityProvider()) - .setRequestTimeout(uint(5000)) - .build() ); } diff --git a/milo-examples/server-examples/src/main/java/org/eclipse/milo/examples/server/ExampleServer.java b/milo-examples/server-examples/src/main/java/org/eclipse/milo/examples/server/ExampleServer.java index d42f5c5b7..5c01dee89 100644 --- a/milo-examples/server-examples/src/main/java/org/eclipse/milo/examples/server/ExampleServer.java +++ b/milo-examples/server-examples/src/main/java/org/eclipse/milo/examples/server/ExampleServer.java @@ -26,6 +26,7 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.api.config.EndpointConfig; import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig; import org.eclipse.milo.opcua.sdk.server.identity.CompositeValidator; import org.eclipse.milo.opcua.sdk.server.identity.UsernameIdentityValidator; @@ -34,6 +35,7 @@ import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaRuntimeException; import org.eclipse.milo.opcua.stack.core.security.DefaultCertificateManager; +import org.eclipse.milo.opcua.stack.core.security.DefaultServerCertificateValidator; import org.eclipse.milo.opcua.stack.core.security.DefaultTrustListManager; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; @@ -43,8 +45,8 @@ import org.eclipse.milo.opcua.stack.core.types.structured.BuildInfo; import org.eclipse.milo.opcua.stack.core.util.CertificateUtil; import org.eclipse.milo.opcua.stack.core.util.NonceUtil; -import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; -import org.eclipse.milo.opcua.stack.server.security.DefaultServerCertificateValidator; +import org.eclipse.milo.opcua.stack.transport.server.tcp.OpcTcpServerTransport; +import org.eclipse.milo.opcua.stack.transport.server.tcp.OpcTcpServerTransportConfig; import org.slf4j.LoggerFactory; import static org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig.USER_TOKEN_POLICY_ANONYMOUS; @@ -142,7 +144,7 @@ public ExampleServer() throws Exception { ) ); - Set endpointConfigurations = createEndpointConfigurations(certificate); + Set endpointConfigurations = createEndpointConfigs(certificate); OpcUaServerConfig serverConfig = OpcUaServerConfig.builder() .setApplicationUri(applicationUri) @@ -162,14 +164,21 @@ public ExampleServer() throws Exception { .setProductUri("urn:eclipse:milo:example-server") .build(); - server = new OpcUaServer(serverConfig); + server = new OpcUaServer(serverConfig, transportProfile -> { + assert transportProfile == TransportProfile.TCP_UASC_UABINARY; + + OpcTcpServerTransportConfig transportConfig = + OpcTcpServerTransportConfig.newBuilder().build(); + + return new OpcTcpServerTransport(transportConfig); + }); exampleNamespace = new ExampleNamespace(server); exampleNamespace.startup(); } - private Set createEndpointConfigurations(X509Certificate certificate) { - var endpointConfigurations = new LinkedHashSet(); + private Set createEndpointConfigs(X509Certificate certificate) { + var endpointConfigs = new LinkedHashSet(); List bindAddresses = List.of("0.0.0.0"); @@ -179,7 +188,7 @@ private Set createEndpointConfigurations(X509Certificate for (String bindAddress : bindAddresses) { for (String hostname : hostnames) { - EndpointConfiguration.Builder builder = EndpointConfiguration.newBuilder() + EndpointConfig.Builder builder = EndpointConfig.newBuilder() .setBindAddress(bindAddress) .setHostname(hostname) .setPath("/milo") @@ -191,14 +200,14 @@ private Set createEndpointConfigurations(X509Certificate ); - EndpointConfiguration.Builder noSecurityBuilder = builder.copy() + EndpointConfig.Builder noSecurityBuilder = builder.copy() .setSecurityPolicy(SecurityPolicy.None) .setSecurityMode(MessageSecurityMode.None); - endpointConfigurations.add(buildTcpEndpoint(noSecurityBuilder)); + endpointConfigs.add(buildTcpEndpoint(noSecurityBuilder)); // TCP Basic256Sha256 / SignAndEncrypt - endpointConfigurations.add(buildTcpEndpoint( + endpointConfigs.add(buildTcpEndpoint( builder.copy() .setSecurityPolicy(SecurityPolicy.Basic256Sha256) .setSecurityMode(MessageSecurityMode.SignAndEncrypt)) @@ -215,19 +224,19 @@ private Set createEndpointConfigurations(X509Certificate * its base address. */ - EndpointConfiguration.Builder discoveryBuilder = builder.copy() + EndpointConfig.Builder discoveryBuilder = builder.copy() .setPath("/milo/discovery") .setSecurityPolicy(SecurityPolicy.None) .setSecurityMode(MessageSecurityMode.None); - endpointConfigurations.add(buildTcpEndpoint(discoveryBuilder)); + endpointConfigs.add(buildTcpEndpoint(discoveryBuilder)); } } - return endpointConfigurations; + return endpointConfigs; } - private static EndpointConfiguration buildTcpEndpoint(EndpointConfiguration.Builder base) { + private static EndpointConfig buildTcpEndpoint(EndpointConfig.Builder base) { return base.copy() .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) .setBindPort(TCP_BIND_PORT) diff --git a/opc-ua-sdk/dtd-core/src/main/java/org/eclipse/milo/opcua/sdk/core/dtd/BinaryDataTypeDictionaryInitializer.java b/opc-ua-sdk/dtd-core/src/main/java/org/eclipse/milo/opcua/sdk/core/dtd/BinaryDataTypeDictionaryInitializer.java index 2d91dce66..c9c0bae8d 100644 --- a/opc-ua-sdk/dtd-core/src/main/java/org/eclipse/milo/opcua/sdk/core/dtd/BinaryDataTypeDictionaryInitializer.java +++ b/opc-ua-sdk/dtd-core/src/main/java/org/eclipse/milo/opcua/sdk/core/dtd/BinaryDataTypeDictionaryInitializer.java @@ -1,8 +1,311 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + package org.eclipse.milo.opcua.sdk.core.dtd; import org.eclipse.milo.opcua.stack.core.NamespaceTable; import org.eclipse.milo.opcua.stack.core.types.DataTypeDictionary; -import org.eclipse.milo.opcua.stack.core.types.structured.*; +import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesItem; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesResult; +import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesItem; +import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.AdditionalParametersType; +import org.eclipse.milo.opcua.stack.core.types.structured.AggregateConfiguration; +import org.eclipse.milo.opcua.stack.core.types.structured.AggregateFilter; +import org.eclipse.milo.opcua.stack.core.types.structured.AggregateFilterResult; +import org.eclipse.milo.opcua.stack.core.types.structured.AliasNameDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.Annotation; +import org.eclipse.milo.opcua.stack.core.types.structured.AnonymousIdentityToken; +import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.Argument; +import org.eclipse.milo.opcua.stack.core.types.structured.AttributeOperand; +import org.eclipse.milo.opcua.stack.core.types.structured.AxisInformation; +import org.eclipse.milo.opcua.stack.core.types.structured.BrokerConnectionTransportDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.BrokerDataSetReaderTransportDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.BrokerDataSetWriterTransportDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.BrokerWriterGroupTransportDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowsePath; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowsePathResult; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowsePathTarget; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResult; +import org.eclipse.milo.opcua.stack.core.types.structured.BuildInfo; +import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodResult; +import org.eclipse.milo.opcua.stack.core.types.structured.CallRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CallResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CancelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CancelResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ChannelSecurityToken; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSecureChannelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSecureChannelResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSessionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ComplexNumberType; +import org.eclipse.milo.opcua.stack.core.types.structured.ConfigurationVersionDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ContentFilter; +import org.eclipse.milo.opcua.stack.core.types.structured.ContentFilterElement; +import org.eclipse.milo.opcua.stack.core.types.structured.ContentFilterElementResult; +import org.eclipse.milo.opcua.stack.core.types.structured.ContentFilterResult; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateMonitoredItemsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSubscriptionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSubscriptionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CurrencyUnitType; +import org.eclipse.milo.opcua.stack.core.types.structured.DataChangeFilter; +import org.eclipse.milo.opcua.stack.core.types.structured.DataChangeNotification; +import org.eclipse.milo.opcua.stack.core.types.structured.DataSetMetaDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.DataSetReaderDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.DataSetWriterDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.DataTypeAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.DataTypeNode; +import org.eclipse.milo.opcua.stack.core.types.structured.DatagramConnectionTransport2DataType; +import org.eclipse.milo.opcua.stack.core.types.structured.DatagramConnectionTransportDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.DatagramDataSetReaderTransportDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.DatagramWriterGroupTransport2DataType; +import org.eclipse.milo.opcua.stack.core.types.structured.DatagramWriterGroupTransportDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.DecimalDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteAtTimeDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteEventDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteMonitoredItemsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesItem; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteRawModifiedDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesItem; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteSubscriptionsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteSubscriptionsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DiscoveryConfiguration; +import org.eclipse.milo.opcua.stack.core.types.structured.DoubleComplexNumberType; +import org.eclipse.milo.opcua.stack.core.types.structured.EUInformation; +import org.eclipse.milo.opcua.stack.core.types.structured.ElementOperand; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointConfiguration; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointType; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointUrlListDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.EnumDefinition; +import org.eclipse.milo.opcua.stack.core.types.structured.EnumDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.EnumField; +import org.eclipse.milo.opcua.stack.core.types.structured.EnumValueType; +import org.eclipse.milo.opcua.stack.core.types.structured.EphemeralKeyType; +import org.eclipse.milo.opcua.stack.core.types.structured.EventFieldList; +import org.eclipse.milo.opcua.stack.core.types.structured.EventFilter; +import org.eclipse.milo.opcua.stack.core.types.structured.EventFilterResult; +import org.eclipse.milo.opcua.stack.core.types.structured.EventNotificationList; +import org.eclipse.milo.opcua.stack.core.types.structured.FieldMetaData; +import org.eclipse.milo.opcua.stack.core.types.structured.FieldTargetDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.FilterOperand; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersOnNetworkRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersOnNetworkResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.GenericAttributeValue; +import org.eclipse.milo.opcua.stack.core.types.structured.GenericAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryData; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryEvent; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryEventFieldList; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryModifiedData; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadResult; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadValueId; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateResult; +import org.eclipse.milo.opcua.stack.core.types.structured.InstanceNode; +import org.eclipse.milo.opcua.stack.core.types.structured.IssuedIdentityToken; +import org.eclipse.milo.opcua.stack.core.types.structured.JsonDataSetReaderMessageDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.JsonDataSetWriterMessageDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.JsonWriterGroupMessageDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.KeyValuePair; +import org.eclipse.milo.opcua.stack.core.types.structured.LiteralOperand; +import org.eclipse.milo.opcua.stack.core.types.structured.MdnsDiscoveryConfiguration; +import org.eclipse.milo.opcua.stack.core.types.structured.MethodAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.MethodNode; +import org.eclipse.milo.opcua.stack.core.types.structured.ModelChangeStructureDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ModificationInfo; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifyMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifyMonitoredItemsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifySubscriptionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifySubscriptionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateResult; +import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemModifyRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemModifyResult; +import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemNotification; +import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringFilter; +import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringFilterResult; +import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters; +import org.eclipse.milo.opcua.stack.core.types.structured.NetworkAddressUrlDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.NetworkGroupDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.Node; +import org.eclipse.milo.opcua.stack.core.types.structured.NodeAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.NodeReference; +import org.eclipse.milo.opcua.stack.core.types.structured.NodeTypeDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.NotificationData; +import org.eclipse.milo.opcua.stack.core.types.structured.NotificationMessage; +import org.eclipse.milo.opcua.stack.core.types.structured.ObjectAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.ObjectNode; +import org.eclipse.milo.opcua.stack.core.types.structured.ObjectTypeAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.ObjectTypeNode; +import org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ParsingResult; +import org.eclipse.milo.opcua.stack.core.types.structured.PortableNodeId; +import org.eclipse.milo.opcua.stack.core.types.structured.PortableQualifiedName; +import org.eclipse.milo.opcua.stack.core.types.structured.PriorityMappingEntryType; +import org.eclipse.milo.opcua.stack.core.types.structured.ProgramDiagnostic2DataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ProgramDiagnosticDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PubSubConfiguration2DataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PubSubConfigurationDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PubSubConfigurationRefDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PubSubConfigurationValueDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PubSubConnectionDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PubSubKeyPushTargetDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishedDataItemsDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishedDataSetCustomSourceDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishedDataSetDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishedEventsDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishedVariableDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.QueryDataDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.QueryDataSet; +import org.eclipse.milo.opcua.stack.core.types.structured.QueryFirstRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.QueryFirstResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.QueryNextRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.QueryNextResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.Range; +import org.eclipse.milo.opcua.stack.core.types.structured.RationalNumber; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadAnnotationDataDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadAtTimeDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadEventDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadProcessedDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadRawModifiedDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; +import org.eclipse.milo.opcua.stack.core.types.structured.ReaderGroupDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ReceiveQosPriorityDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.RedundantServerDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceDescriptionDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceListEntryDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceNode; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceTypeAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceTypeNode; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServer2Request; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServer2Response; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisteredServer; +import org.eclipse.milo.opcua.stack.core.types.structured.RelativePath; +import org.eclipse.milo.opcua.stack.core.types.structured.RelativePathElement; +import org.eclipse.milo.opcua.stack.core.types.structured.RepublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RepublishResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; +import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; +import org.eclipse.milo.opcua.stack.core.types.structured.SamplingIntervalDiagnosticsDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.SecurityGroupDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.SemanticChangeStructureDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ServerDiagnosticsSummaryDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ServerOnNetwork; +import org.eclipse.milo.opcua.stack.core.types.structured.ServerStatusDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ServiceCounterDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; +import org.eclipse.milo.opcua.stack.core.types.structured.SessionDiagnosticsDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.SessionSecurityDiagnosticsDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.SessionlessInvokeRequestType; +import org.eclipse.milo.opcua.stack.core.types.structured.SessionlessInvokeResponseType; +import org.eclipse.milo.opcua.stack.core.types.structured.SetMonitoringModeRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetMonitoringModeResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.SetPublishingModeRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetPublishingModeResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.SignatureData; +import org.eclipse.milo.opcua.stack.core.types.structured.SignedSoftwareCertificate; +import org.eclipse.milo.opcua.stack.core.types.structured.SimpleAttributeOperand; +import org.eclipse.milo.opcua.stack.core.types.structured.SimpleTypeDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.StandaloneSubscribedDataSetDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.StandaloneSubscribedDataSetRefDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.StatusChangeNotification; +import org.eclipse.milo.opcua.stack.core.types.structured.StatusResult; +import org.eclipse.milo.opcua.stack.core.types.structured.StructureDefinition; +import org.eclipse.milo.opcua.stack.core.types.structured.StructureDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.StructureField; +import org.eclipse.milo.opcua.stack.core.types.structured.SubscribedDataSetMirrorDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.SubscriptionAcknowledgement; +import org.eclipse.milo.opcua.stack.core.types.structured.SubscriptionDiagnosticsDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.TargetVariablesDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ThreeDCartesianCoordinates; +import org.eclipse.milo.opcua.stack.core.types.structured.ThreeDFrame; +import org.eclipse.milo.opcua.stack.core.types.structured.ThreeDOrientation; +import org.eclipse.milo.opcua.stack.core.types.structured.ThreeDVector; +import org.eclipse.milo.opcua.stack.core.types.structured.TimeZoneDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.TransactionErrorType; +import org.eclipse.milo.opcua.stack.core.types.structured.TransferResult; +import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.TransmitQosPriorityDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.TrustListDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.TypeNode; +import org.eclipse.milo.opcua.stack.core.types.structured.UABinaryFileDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.UadpDataSetReaderMessageDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.UadpDataSetWriterMessageDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.UadpWriterGroupMessageDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.UnsignedRationalNumber; +import org.eclipse.milo.opcua.stack.core.types.structured.UpdateDataDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.UpdateEventDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.UpdateStructureDataDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.UserManagementDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.UserNameIdentityToken; +import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; +import org.eclipse.milo.opcua.stack.core.types.structured.VariableAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.VariableNode; +import org.eclipse.milo.opcua.stack.core.types.structured.VariableTypeAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.VariableTypeNode; +import org.eclipse.milo.opcua.stack.core.types.structured.ViewAttributes; +import org.eclipse.milo.opcua.stack.core.types.structured.ViewDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.ViewNode; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue; +import org.eclipse.milo.opcua.stack.core.types.structured.WriterGroupDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.X509IdentityToken; +import org.eclipse.milo.opcua.stack.core.types.structured.XVType; public class BinaryDataTypeDictionaryInitializer extends DataTypeDictionaryInitializer { @Override @@ -74,6 +377,12 @@ protected void initializeStructs(NamespaceTable namespaceTable, TrustListDataType.BINARY_ENCODING_ID.toNodeIdOrThrow(namespaceTable), BinaryDataTypeCodec.from(new TrustListDataType.Codec()) )); + binaryDictionary.registerType(new BinaryDataTypeDictionary.BinaryType( + "TransactionErrorType", + TransactionErrorType.TYPE_ID.toNodeIdOrThrow(namespaceTable), + TransactionErrorType.BINARY_ENCODING_ID.toNodeIdOrThrow(namespaceTable), + BinaryDataTypeCodec.from(new TransactionErrorType.Codec()) + )); binaryDictionary.registerType(new BinaryDataTypeDictionary.BinaryType( "UABinaryFileDataType", UABinaryFileDataType.TYPE_ID.toNodeIdOrThrow(namespaceTable), @@ -386,6 +695,18 @@ protected void initializeStructs(NamespaceTable namespaceTable, PriorityMappingEntryType.BINARY_ENCODING_ID.toNodeIdOrThrow(namespaceTable), BinaryDataTypeCodec.from(new PriorityMappingEntryType.Codec()) )); + binaryDictionary.registerType(new BinaryDataTypeDictionary.BinaryType( + "ReferenceDescriptionDataType", + ReferenceDescriptionDataType.TYPE_ID.toNodeIdOrThrow(namespaceTable), + ReferenceDescriptionDataType.BINARY_ENCODING_ID.toNodeIdOrThrow(namespaceTable), + BinaryDataTypeCodec.from(new ReferenceDescriptionDataType.Codec()) + )); + binaryDictionary.registerType(new BinaryDataTypeDictionary.BinaryType( + "ReferenceListEntryDataType", + ReferenceListEntryDataType.TYPE_ID.toNodeIdOrThrow(namespaceTable), + ReferenceListEntryDataType.BINARY_ENCODING_ID.toNodeIdOrThrow(namespaceTable), + BinaryDataTypeCodec.from(new ReferenceListEntryDataType.Codec()) + )); binaryDictionary.registerType(new BinaryDataTypeDictionary.BinaryType( "RolePermissionType", RolePermissionType.TYPE_ID.toNodeIdOrThrow(namespaceTable), diff --git a/opc-ua-sdk/dtd-reader/src/main/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionaryReader.java b/opc-ua-sdk/dtd-reader/src/main/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionaryReader.java index 4e37bf00d..d39fccd88 100644 --- a/opc-ua-sdk/dtd-reader/src/main/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionaryReader.java +++ b/opc-ua-sdk/dtd-reader/src/main/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionaryReader.java @@ -34,9 +34,9 @@ import io.netty.buffer.CompositeByteBuf; import io.netty.buffer.Unpooled; import jakarta.xml.bind.JAXBException; +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.sdk.client.OpcUaSession; import org.eclipse.milo.opcua.sdk.core.dtd.BsdParser; -import org.eclipse.milo.opcua.stack.client.UaStackClient; import org.eclipse.milo.opcua.stack.core.AttributeId; import org.eclipse.milo.opcua.stack.core.NodeIds; import org.eclipse.milo.opcua.stack.core.StatusCodes; @@ -85,11 +85,11 @@ public class BinaryDataTypeDictionaryReader { private final Logger logger = LoggerFactory.getLogger(getClass()); - private final UaStackClient stackClient; + private final OpcUaClient client; private final OpcUaSession session; - public BinaryDataTypeDictionaryReader(UaStackClient stackClient, OpcUaSession session) { - this.stackClient = stackClient; + public BinaryDataTypeDictionaryReader(OpcUaClient client, OpcUaSession session) { + this.client = client; this.session = session; } @@ -107,7 +107,7 @@ public CompletableFuture> readDataTypeDictionaries() { references -> references.stream() .filter(r -> r.getTypeDefinition().equalTo(NodeIds.DataTypeDictionaryType)) - .flatMap(r -> opt2stream(r.getNodeId().toNodeId(stackClient.getNamespaceTable()))) + .flatMap(r -> opt2stream(r.getNodeId().toNodeId(client.getNamespaceTable()))) ); return dictionaryNodeIds @@ -250,7 +250,7 @@ private CompletableFuture readFragments( return completedFuture(fragmentBuffer); } - }, stackClient.getConfig().getExecutor()); + }, client.getTransport().getConfig().getExecutor()); } private CompletableFuture createTypeDictionaryInfo(NodeId dictionaryNodeId, ByteString bs) { @@ -426,7 +426,7 @@ private CompletableFuture> browseDataTypeDescriptionNodeIds(NodeId return browseResult.thenApply(references -> references.stream() .filter(r -> NodeIds.DataTypeDescriptionType.equalTo(r.getTypeDefinition())) - .flatMap(r -> opt2stream(r.getNodeId().toNodeId(stackClient.getNamespaceTable()))) + .flatMap(r -> opt2stream(r.getNodeId().toNodeId(client.getNamespaceTable()))) .collect(Collectors.toList()) ); } @@ -491,7 +491,7 @@ private CompletableFuture> browseDataTypeEncodingNodeIds(List r.getNodeId() - .toNodeId(stackClient.getNamespaceTable()) + .toNodeId(client.getNamespaceTable()) .orElse(NodeId.NULL_VALUE) ).orElse(NodeId.NULL_VALUE); }); @@ -516,7 +516,7 @@ private CompletableFuture> browseDataTypeIds(List dataTypeE return ref.map(r -> r.getNodeId() - .toNodeId(stackClient.getNamespaceTable()) + .toNodeId(client.getNamespaceTable()) .orElse(NodeId.NULL_VALUE) ).orElse(NodeId.NULL_VALUE); }); @@ -526,9 +526,9 @@ private CompletableFuture> browseDataTypeIds(List dataTypeE } private CompletableFuture> browseNode(BrowseDescription browseDescription) { - RequestHeader requestHeader = stackClient.newRequestHeader( + RequestHeader requestHeader = client.newRequestHeader( session.getAuthenticationToken(), - stackClient.getConfig().getRequestTimeout() + client.getConfig().getRequestTimeout() ); BrowseRequest browseRequest = new BrowseRequest( @@ -538,7 +538,8 @@ private CompletableFuture> browseNode(BrowseDescripti new BrowseDescription[]{browseDescription} ); - return stackClient.sendRequest(browseRequest) + return client.getTransport() + .sendRequestMessage(browseRequest) .thenApply(BrowseResponse.class::cast) .thenApply(r -> Objects.requireNonNull(r.getResults())[0]) .thenCompose(result -> { @@ -577,9 +578,9 @@ private CompletableFuture> browseNextAsync( ByteString continuationPoint, List references) { - RequestHeader requestHeader = stackClient.newRequestHeader( + RequestHeader requestHeader = client.newRequestHeader( session.getAuthenticationToken(), - stackClient.getConfig().getRequestTimeout() + client.getConfig().getRequestTimeout() ); BrowseNextRequest request = new BrowseNextRequest( @@ -588,7 +589,8 @@ private CompletableFuture> browseNextAsync( new ByteString[]{continuationPoint} ); - return stackClient.sendRequest(request) + return client.getTransport() + .sendRequestMessage(request) .thenApply(BrowseNextResponse.class::cast) .thenCompose(response -> { BrowseResult result = l(response.getResults()).get(0); @@ -602,9 +604,9 @@ private CompletableFuture readNode(ReadValueId readValueId) { } private CompletableFuture> readNodes(List readValueIds) { - RequestHeader requestHeader = stackClient.newRequestHeader( + RequestHeader requestHeader = client.newRequestHeader( session.getAuthenticationToken(), - stackClient.getConfig().getRequestTimeout() + client.getConfig().getRequestTimeout() ); ReadRequest readRequest = new ReadRequest( @@ -614,7 +616,8 @@ private CompletableFuture> readNodes(List readValue readValueIds.toArray(new ReadValueId[0]) ); - return stackClient.sendRequest(readRequest) + return client.getTransport() + .sendRequestMessage(readRequest) .thenApply(ReadResponse.class::cast) .thenApply(r -> l(r.getResults())); } diff --git a/opc-ua-sdk/dtd-reader/src/main/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionarySessionInitializer.java b/opc-ua-sdk/dtd-reader/src/main/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionarySessionInitializer.java index 62daf5f6a..914e4b15d 100644 --- a/opc-ua-sdk/dtd-reader/src/main/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionarySessionInitializer.java +++ b/opc-ua-sdk/dtd-reader/src/main/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionarySessionInitializer.java @@ -14,13 +14,13 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.sdk.client.OpcUaSession; import org.eclipse.milo.opcua.sdk.client.dtd.BinaryDataTypeDictionaryReader.TypeDictionaryInfo; import org.eclipse.milo.opcua.sdk.client.session.SessionFsm; import org.eclipse.milo.opcua.sdk.core.dtd.BinaryDataTypeCodec; import org.eclipse.milo.opcua.sdk.core.dtd.BinaryDataTypeDictionary; import org.eclipse.milo.opcua.sdk.core.dtd.BinaryDataTypeDictionary.BinaryType; -import org.eclipse.milo.opcua.stack.client.UaStackClient; import org.eclipse.milo.opcua.stack.core.types.DataTypeManager; import org.eclipse.milo.opcua.stack.core.util.Unit; import org.opcfoundation.opcua.binaryschema.StructuredType; @@ -38,7 +38,7 @@ public BinaryDataTypeDictionarySessionInitializer(CodecFactory codecFactory) { } @Override - public CompletableFuture initialize(UaStackClient client, OpcUaSession session) { + public CompletableFuture initialize(OpcUaClient client, OpcUaSession session) { logger.debug("SessionInitializer: DataTypeDictionary"); var dictionaryReader = new BinaryDataTypeDictionaryReader(client, session); diff --git a/opc-ua-sdk/dtd-reader/src/test/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionaryReaderTest.java b/opc-ua-sdk/dtd-reader/src/test/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionaryReaderTest.java index b945e145b..8122a8a3c 100644 --- a/opc-ua-sdk/dtd-reader/src/test/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionaryReaderTest.java +++ b/opc-ua-sdk/dtd-reader/src/test/java/org/eclipse/milo/opcua/sdk/client/dtd/BinaryDataTypeDictionaryReaderTest.java @@ -17,10 +17,10 @@ import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.sdk.client.OpcUaSession; +import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig; import org.eclipse.milo.opcua.sdk.core.NumericRange; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; import org.eclipse.milo.opcua.stack.core.NodeIds; import org.eclipse.milo.opcua.stack.core.Stack; import org.eclipse.milo.opcua.stack.core.UaException; @@ -31,6 +31,8 @@ import org.eclipse.milo.opcua.stack.core.types.structured.ReadRequest; import org.eclipse.milo.opcua.stack.core.types.structured.ReadResponse; import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; +import org.eclipse.milo.opcua.stack.transport.client.tcp.OpcTcpClientTransport; +import org.eclipse.milo.opcua.stack.transport.client.tcp.OpcTcpClientTransportConfig; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -38,21 +40,29 @@ import org.mockito.Mockito; import static java.util.concurrent.CompletableFuture.completedFuture; +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; import static org.junit.jupiter.api.Assertions.assertNotNull; class BinaryDataTypeDictionaryReaderTest { - private final UaStackClient stackClient = Mockito.mock(UaStackClient.class); - private final UaStackClientConfig config = Mockito.mock(UaStackClientConfig.class); + private final OpcTcpClientTransport transport = Mockito.mock(OpcTcpClientTransport.class); + private final OpcTcpClientTransportConfig transportConfig = Mockito.mock(OpcTcpClientTransportConfig.class); + + private final OpcUaClient client = Mockito.mock(OpcUaClient.class); + private final OpcUaClientConfig clientConfig = Mockito.mock(OpcUaClientConfig.class); + private final OpcUaSession session = Mockito.mock(OpcUaSession.class); private final BinaryDataTypeDictionaryReader dictionaryReader = - new BinaryDataTypeDictionaryReader(stackClient, session); + new BinaryDataTypeDictionaryReader(client, session); @BeforeEach void setUp() { - Mockito.when(stackClient.getConfig()).thenReturn(config); - Mockito.when(config.getExecutor()).thenReturn(Stack.sharedExecutor()); + Mockito.when(client.getConfig()).thenReturn(clientConfig); + Mockito.when(client.getConfig().getRequestTimeout()).thenReturn(uint(5000)); + Mockito.when(client.getTransport()).thenReturn(transport); + Mockito.when(client.getTransport().getConfig()).thenReturn(transportConfig); + Mockito.when(client.getTransport().getConfig().getExecutor()).thenReturn(Stack.sharedExecutor()); } @Test @@ -88,7 +98,7 @@ public void readBuiltinDataTypeDictionaryBytes() throws ExecutionException, Inte private void testReadDataTypeDictionaryBytes(ByteString dictionary, int fragmentSize) throws Exception { Mockito - .when(stackClient.sendRequest(ArgumentMatchers.any(ReadRequest.class))) + .when(transport.sendRequestMessage(ArgumentMatchers.any(ReadRequest.class))) .then(invocationOnMock -> { ReadRequest readRequest = invocationOnMock.getArgument(0); diff --git a/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/UaNodeTest.java b/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/UaNodeTest.java index 777c3107e..e299a821d 100644 --- a/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/UaNodeTest.java +++ b/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/UaNodeTest.java @@ -171,7 +171,7 @@ public void refresh() throws UaException { values.forEach(v -> { assertNotNull(v.getStatusCode()); - assertTrue(v.getStatusCode().isGood()); + assertTrue(v.getStatusCode().isGood() || v.getValue().isNull()); }); } diff --git a/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/test/TestClient.java b/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/test/TestClient.java index 7563a6f10..7b04f0683 100644 --- a/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/test/TestClient.java +++ b/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/test/TestClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -12,9 +12,9 @@ import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.api.config.EndpointConfig; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; @@ -23,7 +23,7 @@ public final class TestClient { private TestClient() {} public static OpcUaClient create(OpcUaServer server) throws UaException { - EndpointConfiguration endpoint = server.getConfig().getEndpoints().iterator().next(); + EndpointConfig endpoint = server.getConfig().getEndpoints().iterator().next(); return OpcUaClient.create( endpoint.getEndpointUrl(), @@ -31,12 +31,12 @@ public static OpcUaClient create(OpcUaServer server) throws UaException { endpoints.stream() .filter(e -> e.getSecurityPolicyUri().equals(endpoint.getSecurityPolicy().getUri())) .findFirst(), - configBuilder -> - configBuilder + transportConfigBuilder -> {}, + clientConfigBuilder -> + clientConfigBuilder .setApplicationName(LocalizedText.english("eclipse milo test client")) .setApplicationUri("urn:eclipse:milo:test:client") - .setRequestTimeout(uint(5000)) - .build() + .setRequestTimeout(uint(5_000)) ); } diff --git a/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/test/TestServer.java b/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/test/TestServer.java index ceae938d0..29bbeed57 100644 --- a/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/test/TestServer.java +++ b/opc-ua-sdk/integration-tests/src/test/java/org/eclipse/milo/opcua/sdk/test/TestServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -24,12 +24,14 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.api.config.EndpointConfig; import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig; import org.eclipse.milo.opcua.sdk.server.identity.UsernameIdentityValidator; import org.eclipse.milo.opcua.sdk.server.util.HostnameUtil; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaRuntimeException; import org.eclipse.milo.opcua.stack.core.security.DefaultCertificateManager; +import org.eclipse.milo.opcua.stack.core.security.DefaultServerCertificateValidator; import org.eclipse.milo.opcua.stack.core.security.DefaultTrustListManager; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; @@ -40,8 +42,8 @@ import org.eclipse.milo.opcua.stack.core.util.CertificateUtil; import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator; import org.eclipse.milo.opcua.stack.core.util.SelfSignedHttpsCertificateBuilder; -import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; -import org.eclipse.milo.opcua.stack.server.security.DefaultServerCertificateValidator; +import org.eclipse.milo.opcua.stack.transport.server.tcp.OpcTcpServerTransport; +import org.eclipse.milo.opcua.stack.transport.server.tcp.OpcTcpServerTransportConfig; import org.slf4j.LoggerFactory; import static org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig.USER_TOKEN_POLICY_ANONYMOUS; @@ -134,7 +136,7 @@ public static OpcUaServer create(int port) throws Exception { StatusCodes.Bad_ConfigurationError, "certificate is missing the application URI")); - Set endpointConfigurations = createEndpointConfigurations(certificate, port); + Set endpointConfigurations = createEndpointConfigs(certificate, port); OpcUaServerConfig serverConfig = OpcUaServerConfig.builder() .setApplicationUri(applicationUri) @@ -150,17 +152,25 @@ public static OpcUaServer create(int port) throws Exception { .setCertificateManager(certificateManager) .setTrustListManager(trustListManager) .setCertificateValidator(certificateValidator) - .setHttpsKeyPair(httpsKeyPair) - .setHttpsCertificateChain(new X509Certificate[]{httpsCertificate}) .setIdentityValidator(identityValidator) .setProductUri("urn:eclipse:milo:example-server") .build(); - return new OpcUaServer(serverConfig); + + return new OpcUaServer(serverConfig, transportProfile -> { + if (transportProfile == TransportProfile.TCP_UASC_UABINARY) { + OpcTcpServerTransportConfig transportConfig = + OpcTcpServerTransportConfig.newBuilder().build(); + + return new OpcTcpServerTransport(transportConfig); + } else { + throw new RuntimeException("unexpected TransportProfile: " + transportProfile); + } + }); } - private static Set createEndpointConfigurations(X509Certificate certificate, int port) { - Set endpointConfigurations = new LinkedHashSet<>(); + private static Set createEndpointConfigs(X509Certificate certificate, int port) { + Set endpointConfigurations = new LinkedHashSet<>(); var bindAddresses = new ArrayList(); bindAddresses.add("localhost"); @@ -169,7 +179,7 @@ private static Set createEndpointConfigurations(X509Certi for (String bindAddress : bindAddresses) { for (String hostname : hostnames) { - EndpointConfiguration.Builder builder = EndpointConfiguration.newBuilder() + EndpointConfig.Builder builder = EndpointConfig.newBuilder() .setBindAddress(bindAddress) .setHostname(hostname) .setPath("/test") @@ -180,7 +190,7 @@ private static Set createEndpointConfigurations(X509Certi USER_TOKEN_POLICY_X509); - EndpointConfiguration.Builder noSecurityBuilder = builder.copy() + EndpointConfig.Builder noSecurityBuilder = builder.copy() .setSecurityPolicy(SecurityPolicy.None) .setSecurityMode(MessageSecurityMode.None); @@ -207,7 +217,7 @@ private static Set createEndpointConfigurations(X509Certi * its base address. */ - EndpointConfiguration.Builder discoveryBuilder = builder.copy() + EndpointConfig.Builder discoveryBuilder = builder.copy() .setPath("/test/discovery") .setSecurityPolicy(SecurityPolicy.None) .setSecurityMode(MessageSecurityMode.None); @@ -219,7 +229,7 @@ private static Set createEndpointConfigurations(X509Certi return endpointConfigurations; } - private static EndpointConfiguration buildTcpEndpoint(int port, EndpointConfiguration.Builder base) { + private static EndpointConfig buildTcpEndpoint(int port, EndpointConfig.Builder base) { return base.copy() .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) .setBindPort(port) diff --git a/opc-ua-sdk/sdk-client/pom.xml b/opc-ua-sdk/sdk-client/pom.xml index e4037025a..4ec717611 100644 --- a/opc-ua-sdk/sdk-client/pom.xml +++ b/opc-ua-sdk/sdk-client/pom.xml @@ -27,8 +27,8 @@ org.eclipse.milo - stack-client - ${project.version} + transport + 2.0.0-SNAPSHOT org.eclipse.milo diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/BrowseHelper.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/BrowseHelper.java index 2593f7c83..ce0017205 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/BrowseHelper.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/BrowseHelper.java @@ -15,7 +15,6 @@ import java.util.List; import java.util.concurrent.CompletableFuture; -import org.eclipse.milo.opcua.stack.client.UaStackClient; import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; @@ -48,12 +47,12 @@ public static CompletableFuture> browse( return client.getSession().thenCompose( session -> - browse(client.getStackClient(), session, browseDescription, maxReferencesPerNode) + browse(client, session, browseDescription, maxReferencesPerNode) ); } public static CompletableFuture> browse( - UaStackClient client, + OpcUaClient client, OpcUaSession session, BrowseDescription browseDescription, UInteger maxReferencesPerNode @@ -73,18 +72,21 @@ public static CompletableFuture> browse( new BrowseDescription[]{browseDescription} ); - return client.sendRequest(browseRequest).thenApply(BrowseResponse.class::cast).thenCompose(response -> { - BrowseResult result = response.getResults()[0]; + return client.getTransport() + .sendRequestMessage(browseRequest) + .thenApply(BrowseResponse.class::cast) + .thenCompose(response -> { + BrowseResult result = response.getResults()[0]; - List references = - Collections.synchronizedList(new ArrayList<>()); + List references = + Collections.synchronizedList(new ArrayList<>()); - return maybeBrowseNext(client, session, references, result); - }); + return maybeBrowseNext(client, session, references, result); + }); } private static CompletableFuture> maybeBrowseNext( - UaStackClient client, + OpcUaClient client, OpcUaSession session, List references, BrowseResult result @@ -106,7 +108,7 @@ private static CompletableFuture> maybeBrowseNext( } private static CompletableFuture> browseNext( - UaStackClient client, + OpcUaClient client, OpcUaSession session, ByteString continuationPoint, List references @@ -121,11 +123,14 @@ private static CompletableFuture> browseNext( new ByteString[]{continuationPoint} ); - return client.sendRequest(browseNextRequest).thenApply(BrowseNextResponse.class::cast).thenCompose(response -> { - BrowseResult result = response.getResults()[0]; + return client.getTransport() + .sendRequestMessage(browseNextRequest) + .thenApply(BrowseNextResponse.class::cast) + .thenCompose(response -> { + BrowseResult result = response.getResults()[0]; - return maybeBrowseNext(client, session, references, result); - }); + return maybeBrowseNext(client, session, references, result); + }); } } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DataTypeCodecSessionInitializer.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DataTypeCodecSessionInitializer.java index 339a36aeb..d1fc06f08 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DataTypeCodecSessionInitializer.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DataTypeCodecSessionInitializer.java @@ -17,7 +17,6 @@ import org.eclipse.milo.opcua.sdk.core.types.DynamicCodecFactory; import org.eclipse.milo.opcua.sdk.core.typetree.DataType; import org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree; -import org.eclipse.milo.opcua.stack.client.UaStackClient; import org.eclipse.milo.opcua.stack.core.NodeIds; import org.eclipse.milo.opcua.stack.core.encoding.DataTypeCodec; import org.eclipse.milo.opcua.stack.core.util.Tree; @@ -50,27 +49,27 @@ public DataTypeCodecSessionInitializer(CodecFactory codecFactory) { } @Override - public CompletableFuture initialize(UaStackClient stackClient, OpcUaSession session) { + public CompletableFuture initialize(OpcUaClient client, OpcUaSession session) { String treeKey = DataTypeTreeSessionInitializer.SESSION_ATTRIBUTE_KEY; Object dataTypeTree = session.getAttribute(treeKey); if (dataTypeTree instanceof DataTypeTree) { - registerCodecs(stackClient, (DataTypeTree) dataTypeTree); + registerCodecs(client, (DataTypeTree) dataTypeTree); return CompletableFuture.completedFuture(Unit.VALUE); } else { - return DataTypeTreeBuilder.buildAsync(stackClient, session) + return DataTypeTreeBuilder.buildAsync(client, session) .thenAccept(tree -> { session.setAttribute(treeKey, tree); - registerCodecs(stackClient, tree); + registerCodecs(client, tree); }) .thenApply(v -> Unit.VALUE); } } - private void registerCodecs(UaStackClient stackClient, DataTypeTree dataTypeTree) { + private void registerCodecs(OpcUaClient client, DataTypeTree dataTypeTree) { Tree structureNode = dataTypeTree.getTreeNode(NodeIds.Structure); if (structureNode != null) { @@ -81,7 +80,7 @@ private void registerCodecs(UaStackClient stackClient, DataTypeTree dataTypeTree dataType.getBrowseName(), dataType.getNodeId() ); - stackClient.getDynamicDataTypeManager().registerType( + client.getDynamicDataTypeManager().registerType( dataType.getNodeId(), codecFactory.create(dataType, dataTypeTree), dataType.getBinaryEncodingId(), diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DataTypeTreeSessionInitializer.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DataTypeTreeSessionInitializer.java index afb1476db..282082432 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DataTypeTreeSessionInitializer.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DataTypeTreeSessionInitializer.java @@ -15,7 +15,6 @@ import org.eclipse.milo.opcua.sdk.client.session.SessionFsm; import org.eclipse.milo.opcua.sdk.client.typetree.DataTypeTreeBuilder; import org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree; -import org.eclipse.milo.opcua.stack.client.UaStackClient; import org.eclipse.milo.opcua.stack.core.util.Unit; /** @@ -33,8 +32,8 @@ public class DataTypeTreeSessionInitializer implements SessionFsm.SessionInitial public static final String SESSION_ATTRIBUTE_KEY = "dataTypeTree"; @Override - public CompletableFuture initialize(UaStackClient stackClient, OpcUaSession session) { - return DataTypeTreeBuilder.buildAsync(stackClient, session) + public CompletableFuture initialize(OpcUaClient client, OpcUaSession session) { + return DataTypeTreeBuilder.buildAsync(client, session) .thenAccept(tree -> session.setAttribute(SESSION_ATTRIBUTE_KEY, tree)) .thenApply(v -> Unit.VALUE); } diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/DiscoveryClient.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DiscoveryClient.java similarity index 53% rename from opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/DiscoveryClient.java rename to opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DiscoveryClient.java index 21a812a1c..185dd23fc 100644 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/DiscoveryClient.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/DiscoveryClient.java @@ -8,18 +8,33 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.client; +package org.eclipse.milo.opcua.sdk.client; +import java.security.KeyPair; +import java.security.cert.X509Certificate; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; +import org.eclipse.milo.opcua.stack.core.NamespaceTable; +import org.eclipse.milo.opcua.stack.core.ServerTable; import org.eclipse.milo.opcua.stack.core.Stack; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; +import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; +import org.eclipse.milo.opcua.stack.core.encoding.EncodingManager; +import org.eclipse.milo.opcua.stack.core.encoding.OpcUaEncodingManager; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.ClientCertificateValidator; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +import org.eclipse.milo.opcua.stack.core.types.DataTypeManager; +import org.eclipse.milo.opcua.stack.core.types.OpcUaDataTypeManager; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; @@ -27,27 +42,74 @@ import org.eclipse.milo.opcua.stack.core.types.structured.FindServersResponse; import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsRequest; import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisteredServer; import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; +import org.eclipse.milo.opcua.stack.transport.client.OpcClientTransport; +import org.eclipse.milo.opcua.stack.transport.client.tcp.OpcTcpClientTransport; +import org.eclipse.milo.opcua.stack.transport.client.tcp.OpcTcpClientTransportConfig; +import org.eclipse.milo.opcua.stack.transport.client.tcp.OpcTcpClientTransportConfigBuilder; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ubyte; +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; import static org.eclipse.milo.opcua.stack.core.util.FutureUtils.failedFuture; public class DiscoveryClient { - private final UaStackClient stackClient; - - public DiscoveryClient(UaStackClient stackClient) { - this.stackClient = stackClient; + private final ClientApplicationContext applicationContext; + private final OpcClientTransport transport; + + public DiscoveryClient(EndpointDescription endpoint, OpcClientTransport transport) { + this.transport = transport; + + applicationContext = new ClientApplicationContext() { + @Override + public EndpointDescription getEndpoint() { + return endpoint; + } + + @Override + public Optional getKeyPair() { + return Optional.empty(); + } + + @Override + public Optional getCertificate() { + return Optional.empty(); + } + + @Override + public Optional getCertificateChain() { + return Optional.empty(); + } + + @Override + public CertificateValidator getCertificateValidator() { + return new ClientCertificateValidator.InsecureValidator(); + } + + @Override + public EncodingContext getEncodingContext() { + return new DefaultEncodingContext(); + } + + @Override + public UInteger getRequestTimeout() { + return uint(60_000); + } + }; } public CompletableFuture connect() { - return stackClient.connect().thenApply(c -> DiscoveryClient.this); + return transport.connect(applicationContext).thenApply(c -> DiscoveryClient.this); } public CompletableFuture disconnect() { - return stackClient.disconnect().thenApply(c -> DiscoveryClient.this); + return transport.disconnect().thenApply(c -> DiscoveryClient.this); } /** @@ -71,9 +133,9 @@ public CompletableFuture findServers( String[] serverUris ) { - RequestHeader requestHeader = stackClient.newRequestHeader( + RequestHeader requestHeader = newRequestHeader( NodeId.NULL_VALUE, - stackClient.getConfig().getRequestTimeout() + uint(60_000) ); FindServersRequest request = new FindServersRequest( @@ -83,7 +145,7 @@ public CompletableFuture findServers( serverUris ); - return stackClient.sendRequest(request) + return transport.sendRequestMessage(request) .thenApply(FindServersResponse.class::cast); } @@ -102,9 +164,9 @@ public CompletableFuture getEndpoints( String[] profileUris ) { - RequestHeader header = stackClient.newRequestHeader( + RequestHeader header = newRequestHeader( NodeId.NULL_VALUE, - stackClient.getConfig().getRequestTimeout() + uint(60_000) ); GetEndpointsRequest request = new GetEndpointsRequest( @@ -114,10 +176,40 @@ public CompletableFuture getEndpoints( profileUris ); - return stackClient.sendRequest(request) + return transport.sendRequestMessage(request) .thenApply(GetEndpointsResponse.class::cast); } + /** + * Call the RegisterServer service to register {@code server}. + * + * @param server the {@link RegisteredServer} to register. + * @return the {@link RegisterServerResponse} returned by the RegisterServer service. + */ + public CompletableFuture registerServer(RegisteredServer server) { + RequestHeader header = newRequestHeader( + NodeId.NULL_VALUE, + uint(60_000) + ); + + var request = new RegisterServerRequest(header, server); + + return transport.sendRequestMessage(request) + .thenApply(RegisterServerResponse.class::cast); + } + + public RequestHeader newRequestHeader(NodeId authToken, UInteger requestTimeout) { + return new RequestHeader( + authToken, + DateTime.now(), + uint(0), + uint(0), + null, + requestTimeout, + null + ); + } + /** * Query the FindServers service at the {@code endpointUrl}. *

@@ -138,12 +230,13 @@ public static CompletableFuture> findServers(String * {@link #getEndpoints(String)} call to discover the endpoints for that server. * * @param endpointUrl the endpoint URL to find servers at. - * @param customizer a {@link Consumer} that accepts a {@link UaStackClientConfigBuilder} for customization. + * @param customizer a {@link Consumer} that accepts a + * {@link OpcTcpClientTransportConfigBuilder} for customization. * @return a List of {@link ApplicationDescription}s returned by the FindServers service. */ public static CompletableFuture> findServers( String endpointUrl, - Consumer customizer + Consumer customizer ) { EndpointDescription endpoint = new EndpointDescription( @@ -157,25 +250,18 @@ public static CompletableFuture> findServers( ubyte(0) ); - UaStackClientConfigBuilder builder = UaStackClientConfig.builder(); - builder.setEndpoint(endpoint); - customizer.accept(builder); + OpcTcpClientTransportConfigBuilder configBuilder = OpcTcpClientTransportConfig.newBuilder(); + customizer.accept(configBuilder); - UaStackClientConfig config = builder.build(); + OpcTcpClientTransportConfig config = configBuilder.build(); + var transport = new OpcTcpClientTransport(config); - try { - UaStackClient stackClient = UaStackClient.create(config); + DiscoveryClient discoveryClient = new DiscoveryClient(endpoint, transport); - DiscoveryClient discoveryClient = new DiscoveryClient(stackClient); - - return discoveryClient - .connect() - .thenCompose(c -> c.findServers(endpointUrl, new String[0], new String[0])) - .whenComplete((e, ex) -> discoveryClient.disconnect()) - .thenApply(response -> l(response.getServers())); - } catch (UaException e) { - return failedFuture(e); - } + return discoveryClient.connect() + .thenCompose(c -> c.findServers(endpointUrl, new String[0], new String[0])) + .whenComplete((e, ex) -> discoveryClient.disconnect()) + .thenApply(response -> l(response.getServers())); } /** @@ -192,12 +278,13 @@ public static CompletableFuture> getEndpoints(String e * Query the GetEndpoints service at {@code endpointUrl}. * * @param endpointUrl the endpoint URL to get endpoints from. - * @param customizer a {@link Consumer} that accepts a {@link UaStackClientConfigBuilder} for customization. + * @param customizer a {@link Consumer} that accepts a + * {@link OpcTcpClientTransportConfigBuilder} for customization. * @return a List of {@link EndpointDescription}s returned by the GetEndpoints service. */ public static CompletableFuture> getEndpoints( String endpointUrl, - Consumer customizer + Consumer customizer ) { String scheme = EndpointUtil.getScheme(endpointUrl); @@ -235,7 +322,7 @@ public static CompletableFuture> getEndpoints( private static CompletableFuture> getEndpoints( String endpointUrl, String profileUri, - Consumer customizer + Consumer customizer ) { EndpointDescription endpoint = new EndpointDescription( @@ -249,25 +336,50 @@ private static CompletableFuture> getEndpoints( ubyte(0) ); - UaStackClientConfigBuilder builder = UaStackClientConfig.builder(); - builder.setEndpoint(endpoint); - customizer.accept(builder); + OpcTcpClientTransportConfigBuilder configBuilder = OpcTcpClientTransportConfig.newBuilder(); + customizer.accept(configBuilder); + + OpcTcpClientTransportConfig config = configBuilder.build(); + var transport = new OpcTcpClientTransport(config); + + DiscoveryClient discoveryClient = new DiscoveryClient(endpoint, transport); + + return discoveryClient.connect() + .thenCompose(c -> c.getEndpoints(endpointUrl, new String[0], new String[]{profileUri})) + .whenComplete((e, ex) -> discoveryClient.disconnect()) + .thenApply(response -> l(response.getEndpoints())); + } + + private static class DefaultEncodingContext implements EncodingContext { - UaStackClientConfig config = builder.build(); + private final NamespaceTable namespaceTable = new NamespaceTable(); + private final ServerTable serverTable = new ServerTable(); - try { - UaStackClient stackClient = UaStackClient.create(config); + @Override + public DataTypeManager getDataTypeManager() { + return OpcUaDataTypeManager.getInstance(); + } + + @Override + public EncodingManager getEncodingManager() { + return OpcUaEncodingManager.getInstance(); + } - DiscoveryClient discoveryClient = new DiscoveryClient(stackClient); + @Override + public EncodingLimits getEncodingLimits() { + return EncodingLimits.DEFAULT; + } - return discoveryClient - .connect() - .thenCompose(c -> c.getEndpoints(endpointUrl, new String[0], new String[]{profileUri})) - .whenComplete((e, ex) -> discoveryClient.disconnect()) - .thenApply(response -> l(response.getEndpoints())); - } catch (UaException e) { - return failedFuture(e); + @Override + public NamespaceTable getNamespaceTable() { + return namespaceTable; } + + @Override + public ServerTable getServerTable() { + return serverTable; + } + } } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/OpcUaClient.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/OpcUaClient.java index bd54ba86f..5da863c87 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/OpcUaClient.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/OpcUaClient.java @@ -10,6 +10,8 @@ package org.eclipse.milo.opcua.sdk.client; +import java.security.KeyPair; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -17,6 +19,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -29,8 +32,6 @@ import org.eclipse.milo.opcua.sdk.client.session.SessionFsm; import org.eclipse.milo.opcua.sdk.client.session.SessionFsmFactory; import org.eclipse.milo.opcua.sdk.client.subscriptions.OpcUaSubscriptionManager; -import org.eclipse.milo.opcua.stack.client.DiscoveryClient; -import org.eclipse.milo.opcua.stack.client.UaStackClient; import org.eclipse.milo.opcua.stack.core.AttributeId; import org.eclipse.milo.opcua.stack.core.NamespaceTable; import org.eclipse.milo.opcua.stack.core.NodeIds; @@ -39,12 +40,18 @@ import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.UaServiceFaultException; +import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; +import org.eclipse.milo.opcua.stack.core.encoding.DefaultEncodingManager; import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; +import org.eclipse.milo.opcua.stack.core.encoding.EncodingManager; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; import org.eclipse.milo.opcua.stack.core.types.DataTypeManager; +import org.eclipse.milo.opcua.stack.core.types.DefaultDataTypeManager; import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; @@ -126,13 +133,20 @@ import org.eclipse.milo.opcua.stack.core.types.structured.WriteResponse; import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue; import org.eclipse.milo.opcua.stack.core.util.ExecutionQueue; +import org.eclipse.milo.opcua.stack.core.util.LongSequence; import org.eclipse.milo.opcua.stack.core.util.ManifestUtil; import org.eclipse.milo.opcua.stack.core.util.Namespaces; import org.eclipse.milo.opcua.stack.core.util.Unit; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; +import org.eclipse.milo.opcua.stack.transport.client.OpcClientTransport; +import org.eclipse.milo.opcua.stack.transport.client.tcp.OpcTcpClientTransport; +import org.eclipse.milo.opcua.stack.transport.client.tcp.OpcTcpClientTransportConfig; +import org.eclipse.milo.opcua.stack.transport.client.tcp.OpcTcpClientTransportConfigBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.eclipse.milo.opcua.sdk.client.session.SessionFsm.SessionInitializer; +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; public class OpcUaClient implements UaClient { @@ -155,9 +169,10 @@ public class OpcUaClient implements UaClient { * @throws UaException if the client could not be created (e.g. transport/encoding not supported). */ public static OpcUaClient create(OpcUaClientConfig config) throws UaException { - UaStackClient stackClient = UaStackClient.create(config); + OpcTcpClientTransportConfig transportConfig = OpcTcpClientTransportConfig.newBuilder().build(); + var transport = new OpcTcpClientTransport(transportConfig); - return new OpcUaClient(config, stackClient); + return new OpcUaClient(config, transport); } /** @@ -165,7 +180,7 @@ public static OpcUaClient create(OpcUaClientConfig config) throws UaException { * {@link OpcUaClient} with the default configuration. *

* If the server is not configured with an endpoint with no security or authentication you - * must use {@link #create(String, Function, Function)} to select an endpoint and configure + * must use {@link #create(String, Function, Consumer, Consumer)} to select an endpoint and configure * any certificates or identity provider that the selected endpoint would require. * * @param endpointUrl the endpoint URL of the server to connect to and get endpoints from. @@ -186,27 +201,31 @@ public static OpcUaClient create(String endpointUrl) throws UaException { endpoints -> endpoints.stream() .filter(predicate) .findFirst(), - OpcUaClientConfigBuilder::build + b -> {}, + b -> {} ); } /** - * Create and configure an {@link OpcUaClient} by selecting an {@link EndpointDescription} from a list of endpoints - * retrieved via the GetEndpoints service from the server at {@code endpointUrl} and building an - * {@link OpcUaClientConfig} using that endpoint. + * Create and configure an {@link OpcUaClient} by selecting an {@link EndpointDescription} from + * a list of endpoints retrieved via the GetEndpoints service from the server at {@code endpointUrl} + * and building an {@link OpcUaClientConfig} using that endpoint. * - * @param endpointUrl the endpoint URL of the server to connect to and retrieve endpoints from. - * @param selectEndpoint a function that selects the {@link EndpointDescription} to connect to from the list of - * endpoints from the server. - * @param buildConfig a function that configures an {@link OpcUaClientConfigBuilder} and then builds and returns - * an {@link OpcUaClientConfig}. + * @param endpointUrl the endpoint URL of the server to connect to and retrieve endpoints from. + * @param selectEndpoint a function that selects the {@link EndpointDescription} to connect + * to from the list of endpoints from the server. + * @param configureTransport a Consumer that receives an {@link OpcTcpClientTransportConfigBuilder} + * that can be used to configure the transport. + * @param configureClient a Consumer that receives an {@link OpcUaClientConfigBuilder} that + * can be used to configure the client. * @return a configured {@link OpcUaClient}. * @throws UaException if the endpoints could not be retrieved or the client could not be created. */ public static OpcUaClient create( String endpointUrl, Function, Optional> selectEndpoint, - Function buildConfig + Consumer configureTransport, + Consumer configureClient ) throws UaException { try { @@ -220,10 +239,16 @@ public static OpcUaClient create( ) ); - OpcUaClientConfigBuilder builder = OpcUaClientConfig.builder() - .setEndpoint(endpoint); + OpcTcpClientTransportConfigBuilder transportConfigBuilder = OpcTcpClientTransportConfig.newBuilder(); + configureTransport.accept(transportConfigBuilder); - return create(buildConfig.apply(builder)); + OpcUaClientConfigBuilder clientConfigBuilder = OpcUaClientConfig.builder().setEndpoint(endpoint); + configureClient.accept(clientConfigBuilder); + OpcUaClientConfig clientConfig = clientConfigBuilder.build(); + + var transport = new OpcTcpClientTransport(transportConfigBuilder.build()); + + return new OpcUaClient(clientConfig, transport); } catch (InterruptedException | ExecutionException e) { if (!endpointUrl.endsWith("/discovery")) { StringBuilder discoveryUrl = new StringBuilder(endpointUrl); @@ -232,7 +257,7 @@ public static OpcUaClient create( } discoveryUrl.append("discovery"); - return create(discoveryUrl.toString(), selectEndpoint, buildConfig); + return create(discoveryUrl.toString(), selectEndpoint, configureTransport, configureClient); } else { throw UaException.extract(e) .orElseGet(() -> new UaException(e)); @@ -242,24 +267,137 @@ public static OpcUaClient create( private final Logger logger = LoggerFactory.getLogger(getClass()); + private final LongSequence requestHandles = new LongSequence(0, UInteger.MAX_VALUE); + private final List faultListeners = new CopyOnWriteArrayList<>(); private final ExecutionQueue faultNotificationQueue; private final AddressSpace addressSpace; + private final NamespaceTable namespaceTable = new NamespaceTable(); + private final ServerTable serverTable = new ServerTable(); + private final ObjectTypeManager objectTypeManager = new ObjectTypeManager(); + private final VariableTypeManager variableTypeManager = new VariableTypeManager(); + private final EncodingManager encodingManager = + DefaultEncodingManager.createAndInitialize(); + + private final DataTypeManager staticDataTypeManager = + DefaultDataTypeManager.createAndInitialize(namespaceTable); + + private final DataTypeManager dynamicDataTypeManager = + DefaultDataTypeManager.createAndInitialize(namespaceTable); + + private final EncodingContext staticEncodingContext; + private final EncodingContext dynamicEncodingContext; + private final OpcUaSubscriptionManager subscriptionManager; private final SessionFsm sessionFsm; + private final ClientApplicationContext applicationContext; + private final OpcUaClientConfig config; - private final UaStackClient stackClient; - public OpcUaClient(OpcUaClientConfig config, UaStackClient stackClient) { + private final OpcClientTransport transport; + + + public OpcUaClient(OpcUaClientConfig config, OpcClientTransport transport) { this.config = config; - this.stackClient = stackClient; + this.transport = transport; + + staticEncodingContext = new EncodingContext() { + @Override + public DataTypeManager getDataTypeManager() { + return staticDataTypeManager; + } + + @Override + public EncodingManager getEncodingManager() { + return encodingManager; + } + + @Override + public EncodingLimits getEncodingLimits() { + return config.getEncodingLimits(); + } + + @Override + public NamespaceTable getNamespaceTable() { + return namespaceTable; + } + + @Override + public ServerTable getServerTable() { + return serverTable; + } + }; + + dynamicEncodingContext = new EncodingContext() { + @Override + public DataTypeManager getDataTypeManager() { + return dynamicDataTypeManager; + } + + @Override + public EncodingManager getEncodingManager() { + return encodingManager; + } + + @Override + public EncodingLimits getEncodingLimits() { + return config.getEncodingLimits(); + } + + @Override + public NamespaceTable getNamespaceTable() { + return namespaceTable; + } + + @Override + public ServerTable getServerTable() { + return serverTable; + } + }; + + applicationContext = new ClientApplicationContext() { + @Override + public EndpointDescription getEndpoint() { + return config.getEndpoint(); + } + + @Override + public Optional getKeyPair() { + return config.getKeyPair(); + } + + @Override + public Optional getCertificate() { + return config.getCertificate(); + } + + @Override + public Optional getCertificateChain() { + return config.getCertificateChain(); + } + + @Override + public CertificateValidator getCertificateValidator() { + return config.getCertificateValidator(); + } + + @Override + public EncodingContext getEncodingContext() { + return staticEncodingContext; + } + + @Override + public UInteger getRequestTimeout() { + return config.getRequestTimeout(); + } + }; sessionFsm = SessionFsmFactory.newSessionFsm(this); @@ -291,8 +429,12 @@ public OpcUaClient(OpcUaClientConfig config, UaStackClient stackClient) { .thenApply(results -> { String[] namespaceArray = (String[]) results[0].getValue().getValue(); String[] serverArray = (String[]) results[1].getValue().getValue(); - updateNamespaceTable(namespaceArray); - updateServerTable(serverArray); + if (namespaceArray != null) { + updateNamespaceTable(namespaceArray); + } + if (serverArray != null) { + updateServerTable(serverArray); + } return Unit.VALUE; }) .exceptionally(ex -> { @@ -302,20 +444,13 @@ public OpcUaClient(OpcUaClientConfig config, UaStackClient stackClient) { }); - faultNotificationQueue = new ExecutionQueue(config.getExecutor()); + faultNotificationQueue = new ExecutionQueue(transport.getConfig().getExecutor()); addressSpace = new AddressSpace(this); subscriptionManager = new OpcUaSubscriptionManager(this); - ObjectTypeInitializer.initialize( - stackClient.getNamespaceTable(), - objectTypeManager - ); - - VariableTypeInitializer.initialize( - stackClient.getNamespaceTable(), - variableTypeManager - ); + ObjectTypeInitializer.initialize(namespaceTable, objectTypeManager); + VariableTypeInitializer.initialize(namespaceTable, variableTypeManager); } @Override @@ -323,8 +458,8 @@ public OpcUaClientConfig getConfig() { return config; } - public UaStackClient getStackClient() { - return stackClient; + public OpcClientTransport getTransport() { + return transport; } @Override @@ -341,31 +476,52 @@ public VariableTypeManager getVariableTypeManager() { } /** - * @see UaStackClient#getStaticDataTypeManager() + * Get the client's "static" {@link DataTypeManager}. + *

+ * This {@link DataTypeManager} is for static codecs that serialize classes that exist at + * compile time, e.g. structures from namespace 0 and or code-generated structures. + * + * @return the client's static {@link DataTypeManager}. */ public DataTypeManager getStaticDataTypeManager() { - return stackClient.getStaticDataTypeManager(); + return staticDataTypeManager; } /** - * @see UaStackClient#getDynamicDataTypeManager() + * Get the client's "dynamic" {@link DataTypeManager}. + *

+ * This {@link DataTypeManager} is for dynamic codecs that were created by reading the server's + * DataType Dictionary at runtime and serializes generic representations of structures used by + * instances of a BsdParser implementation. + * + * @return the client's dynamic {@link DataTypeManager}. */ public DataTypeManager getDynamicDataTypeManager() { - return stackClient.getDynamicDataTypeManager(); + return dynamicDataTypeManager; } /** - * @see UaStackClient#getStaticEncodingContext() + * Get a "static" {@link EncodingContext} instance. + *

+ * This {@link EncodingContext} instance returns the client's static {@link DataTypeManager}. + * + * @return a "static" {@link EncodingContext} instance. + * @see #getStaticDataTypeManager() */ public EncodingContext getStaticEncodingContext() { - return stackClient.getStaticEncodingContext(); + return staticEncodingContext; } /** - * @see UaStackClient#getDynamicEncodingContext() + * Get a "dynamic" {@link EncodingContext}. + *

+ * This {@link EncodingContext} instance returns the client's dynamic {@link DataTypeManager}. + * + * @return a "dynamic" {@link EncodingContext}. + * @see #getDynamicDataTypeManager() */ public EncodingContext getDynamicEncodingContext() { - return stackClient.getDynamicEncodingContext(); + return dynamicEncodingContext; } /** @@ -374,7 +530,7 @@ public EncodingContext getDynamicEncodingContext() { * @return the local copy of the server's NamespaceTable (NamespaceArray). */ public NamespaceTable getNamespaceTable() { - return stackClient.getNamespaceTable(); + return namespaceTable; } /** @@ -435,7 +591,7 @@ public CompletableFuture readNamespaceTableAsync() { * @return the local copy of the server's ServerTable (ServerArray). */ public ServerTable getServerTable() { - return stackClient.getServerTable(); + return serverTable; } /** @@ -479,12 +635,12 @@ public CompletableFuture readServerTableAsync() { } ); - CompletableFuture namespaceArray = sendRequest(readRequest) + CompletableFuture serverArray = sendRequest(readRequest) .thenApply(ReadResponse.class::cast) .thenApply(response -> Objects.requireNonNull(response.getResults())) .thenApply(results -> (String[]) results[0].getValue().getValue()); - return namespaceArray + return serverArray .thenAccept(this::updateServerTable) .thenApply(v -> getServerTable()); }); @@ -522,49 +678,52 @@ private void updateServerTable(String[] serverArray) { } /** - * Build a new {@link RequestHeader} using a null authentication token. + * Create a new {@link RequestHeader} with a null authentication token. + *

+ * A unique request handle will be automatically assigned to the header. * * @return a new {@link RequestHeader} with a null authentication token. */ public RequestHeader newRequestHeader() { - return newRequestHeader(NodeId.NULL_VALUE, config.getRequestTimeout()); + return newRequestHeader(NodeId.NULL_VALUE); } /** - * Build a new {@link RequestHeader} using {@code authToken}. + * Create a new {@link RequestHeader} with {@code authToken}. + *

+ * A unique request handle will be automatically assigned to the header. * - * @param authToken the authentication token (from the session) to use. - * @return a new {@link RequestHeader}. + * @param authToken the authentication token to create the header with. + * @return a new {@link RequestHeader} created with {@code authToken}. */ public RequestHeader newRequestHeader(NodeId authToken) { return newRequestHeader(authToken, config.getRequestTimeout()); } /** - * Build a new {@link RequestHeader} using a null authentication token and a custom {@code requestTimeout}. - * - * @param requestTimeout the custom request timeout to use. - * @return a new {@link RequestHeader} with a null authentication token and a custom request timeout. - */ - public RequestHeader newRequestHeader(UInteger requestTimeout) { - return newRequestHeader(NodeId.NULL_VALUE, requestTimeout); - } - - /** - * Build a new {@link RequestHeader} using {@code authToken} and a custom {@code requestTimeout}. + * Create a new {@link RequestHeader} with {@code authToken} and {@code requestTimeout}. + *

+ * A unique request handle will be automatically assigned to the header. * - * @param authToken the authentication token (from the session) to use. - * @param requestTimeout the custom request timeout to use. - * @return a new {@link RequestHeader}. + * @param authToken the authentication token to create the header with. + * @param requestTimeout the timeout hint to create the header with.f + * @return a new {@link RequestHeader} created with {@code authToken} and {@code requestTimeout}. */ public RequestHeader newRequestHeader(NodeId authToken, UInteger requestTimeout) { - return getStackClient().newRequestHeader(authToken, requestTimeout); + return new RequestHeader( + authToken, + DateTime.now(), + uint(requestHandles.getAndIncrement()), + uint(0), + null, + requestTimeout, + null + ); } @Override public CompletableFuture connect() { - return getStackClient() - .connect() + return transport.connect(applicationContext) .thenCompose(c -> sessionFsm.openSession()) .thenApply(s -> OpcUaClient.this); } @@ -575,7 +734,7 @@ public CompletableFuture disconnect() { .closeSession() .exceptionally(ex -> Unit.VALUE) .thenCompose(u -> - getStackClient() + transport .disconnect() .thenApply(c -> OpcUaClient.this)) .exceptionally(ex -> OpcUaClient.this); @@ -586,6 +745,7 @@ public OpcUaSubscriptionManager getSubscriptionManager() { return subscriptionManager; } + @Override public CompletableFuture read(double maxAge, TimestampsToReturn timestampsToReturn, @@ -987,7 +1147,7 @@ public CompletableFuture getSession() { @Override public CompletableFuture sendRequest(UaRequestMessageType request) { - CompletableFuture f = getStackClient().sendRequest(request); + CompletableFuture f = transport.sendRequestMessage(request); if (faultListeners.size() > 0) { f.whenComplete(this::maybeHandleServiceFault); diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/config/OpcUaClientConfig.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/config/OpcUaClientConfig.java index d02c43ed0..4e2a0ac44 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/config/OpcUaClientConfig.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/config/OpcUaClientConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -10,16 +10,60 @@ package org.eclipse.milo.opcua.sdk.client.api.config; +import java.security.KeyPair; +import java.security.cert.X509Certificate; +import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; import org.eclipse.milo.opcua.sdk.client.api.identity.IdentityProvider; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; +import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; +import org.eclipse.milo.opcua.stack.core.security.ClientCertificateValidator; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; import org.eclipse.milo.opcua.stack.core.types.structured.PublishRequest; -public interface OpcUaClientConfig extends UaStackClientConfig { +public interface OpcUaClientConfig { + + /** + * Get the endpoint to connect to. + * + * @return the {@link EndpointDescription} to connect to. + */ + EndpointDescription getEndpoint(); + + /** + * Get the {@link KeyPair} to use. + *

+ * May be absent if connecting without security, must be present if connecting with security. + * + * @return an {@link Optional} containing the {@link KeyPair} to use. + */ + Optional getKeyPair(); + + /** + * Get the {@link X509Certificate} to use. + *

+ * May be absent if connecting without security, must be present if connecting with security. + * + * @return an {@link Optional} containing the {@link X509Certificate} to use. + */ + Optional getCertificate(); + + /** + * Get the {@link X509Certificate} to use as well as any certificates in the certificate chain. + * + * @return the {@link X509Certificate} to use as well as any certificates in the certificate chain. + */ + Optional getCertificateChain(); + + /** + * Get the {@link ClientCertificateValidator} this client will use to validate server certificates when connecting. + * + * @return the validator this client will use to validate server certificates when connecting. + */ + ClientCertificateValidator getCertificateValidator(); /** * @return the name of the client application, as a {@link LocalizedText}. @@ -52,6 +96,16 @@ public interface OpcUaClientConfig extends UaStackClientConfig { */ UInteger getSessionTimeout(); + /** + * @return the request timeout, in milliseconds. + */ + UInteger getRequestTimeout(); + + /** + * @return the {@link EncodingLimits} used by this client. + */ + EncodingLimits getEncodingLimits(); + /** * @return the maximum size for a response from the server. */ @@ -109,7 +163,6 @@ static OpcUaClientConfigBuilder builder() { static OpcUaClientConfigBuilder copy(OpcUaClientConfig config) { OpcUaClientConfigBuilder builder = new OpcUaClientConfigBuilder(); - // UaStackClientConfig values builder.setEndpoint(config.getEndpoint()); config.getKeyPair().ifPresent(builder::setKeyPair); config.getCertificate().ifPresent(builder::setCertificate); @@ -117,17 +170,6 @@ static OpcUaClientConfigBuilder copy(OpcUaClientConfig config) { builder.setApplicationName(config.getApplicationName()); builder.setApplicationUri(config.getApplicationUri()); builder.setProductUri(config.getProductUri()); - builder.setEncodingLimits(config.getEncodingLimits()); - builder.setChannelLifetime(config.getChannelLifetime()); - builder.setExecutor(config.getExecutor()); - builder.setScheduledExecutor(config.getScheduledExecutor()); - builder.setEventLoop(config.getEventLoop()); - builder.setWheelTimer(config.getWheelTimer()); - builder.setConnectTimeout(config.getConnectTimeout()); - builder.setAcknowledgeTimeout(config.getAcknowledgeTimeout()); - builder.setRequestTimeout(config.getRequestTimeout()); - - // OpcUaClientConfig values builder.setSessionName(config.getSessionName()); builder.setSessionTimeout(config.getSessionTimeout()); builder.setRequestTimeout(config.getRequestTimeout()); diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/config/OpcUaClientConfigBuilder.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/config/OpcUaClientConfigBuilder.java index 125a1f355..e9cb6611d 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/config/OpcUaClientConfigBuilder.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/config/OpcUaClientConfigBuilder.java @@ -13,25 +13,25 @@ import java.security.KeyPair; import java.security.cert.X509Certificate; import java.util.Optional; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ScheduledExecutorService; import java.util.function.Supplier; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.util.HashedWheelTimer; import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider; import org.eclipse.milo.opcua.sdk.client.api.identity.IdentityProvider; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfigBuilder; -import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator; import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; +import org.eclipse.milo.opcua.stack.core.security.ClientCertificateValidator; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; -public class OpcUaClientConfigBuilder extends UaStackClientConfigBuilder { +public class OpcUaClientConfigBuilder { + + private EndpointDescription endpoint; + private KeyPair keyPair; + private X509Certificate certificate; + private X509Certificate[] certificateChain; + private ClientCertificateValidator certificateValidator = new ClientCertificateValidator.InsecureValidator(); private LocalizedText applicationName = LocalizedText.english("Eclipse Milo application name not configured"); private String applicationUri = "urn:eclipse:milo:client:applicationUriNotConfigured"; @@ -39,10 +39,12 @@ public class OpcUaClientConfigBuilder extends UaStackClientConfigBuilder { private Supplier sessionName; private String[] sessionLocaleIds = new String[0]; - private UInteger sessionTimeout = uint(120000); + private UInteger sessionTimeout = uint(120_000); + private UInteger requestTimeout = uint(60_000); private IdentityProvider identityProvider = new AnonymousProvider(); + private EncodingLimits encodingLimits = EncodingLimits.DEFAULT; private UInteger maxResponseMessageSize = uint(0); private UInteger maxPendingPublishRequests = uint(UInteger.MAX_VALUE); @@ -81,6 +83,16 @@ public OpcUaClientConfigBuilder setSessionTimeout(UInteger sessionTimeout) { return this; } + public OpcUaClientConfigBuilder setRequestTimeout(UInteger requestTimeout) { + this.requestTimeout = requestTimeout; + return this; + } + + public OpcUaClientConfigBuilder setEncodingLimits(EncodingLimits encodingLimits) { + this.encodingLimits = encodingLimits; + return this; + } + public OpcUaClientConfigBuilder setMaxResponseMessageSize(UInteger maxResponseMessageSize) { this.maxResponseMessageSize = maxResponseMessageSize; return this; @@ -116,94 +128,32 @@ public OpcUaClientConfigBuilder setSubscriptionWatchdogMultiplier(double subscri return this; } - @Override public OpcUaClientConfigBuilder setEndpoint(EndpointDescription endpoint) { - super.setEndpoint(endpoint); + this.endpoint = endpoint; return this; } - @Override public OpcUaClientConfigBuilder setKeyPair(KeyPair keyPair) { - super.setKeyPair(keyPair); + this.keyPair = keyPair; return this; } - @Override public OpcUaClientConfigBuilder setCertificate(X509Certificate certificate) { - super.setCertificate(certificate); + this.certificate = certificate; return this; } - @Override public OpcUaClientConfigBuilder setCertificateChain(X509Certificate[] certificateChain) { - super.setCertificateChain(certificateChain); + this.certificateChain = certificateChain; return this; } - @Override public OpcUaClientConfigBuilder setCertificateValidator(ClientCertificateValidator certificateValidator) { - super.setCertificateValidator(certificateValidator); - return this; - } - - @Override - public OpcUaClientConfigBuilder setChannelLifetime(UInteger channelLifetime) { - super.setChannelLifetime(channelLifetime); - return this; - } - - @Override - public OpcUaClientConfigBuilder setExecutor(ExecutorService executor) { - super.setExecutor(executor); + this.certificateValidator = certificateValidator; return this; } - @Override - public OpcUaClientConfigBuilder setEventLoop(NioEventLoopGroup eventLoop) { - super.setEventLoop(eventLoop); - return this; - } - - @Override - public OpcUaClientConfigBuilder setScheduledExecutor(ScheduledExecutorService scheduledExecutor) { - super.setScheduledExecutor(scheduledExecutor); - return this; - } - - @Override - public OpcUaClientConfigBuilder setWheelTimer(HashedWheelTimer wheelTimer) { - super.setWheelTimer(wheelTimer); - return this; - } - - @Override - public OpcUaClientConfigBuilder setEncodingLimits(EncodingLimits encodingLimits) { - super.setEncodingLimits(encodingLimits); - return this; - } - - @Override - public OpcUaClientConfigBuilder setConnectTimeout(UInteger connectTimeout) { - super.setConnectTimeout(connectTimeout); - return this; - } - - @Override - public OpcUaClientConfigBuilder setAcknowledgeTimeout(UInteger acknowledgeTimeout) { - super.setAcknowledgeTimeout(acknowledgeTimeout); - return this; - } - - @Override - public OpcUaClientConfigBuilder setRequestTimeout(UInteger requestTimeout) { - super.setRequestTimeout(requestTimeout); - return this; - } - - @Override public OpcUaClientConfig build() { - UaStackClientConfig stackClientConfig = super.build(); - if (sessionName == null) { sessionName = () -> String.format("UaSession:%s:%s", applicationName.getText(), @@ -212,13 +162,19 @@ public OpcUaClientConfig build() { } return new OpcUaClientConfigImpl( - stackClientConfig, + endpoint, + keyPair, + certificate, + certificateChain, + certificateValidator, applicationName, applicationUri, productUri, sessionName, sessionLocaleIds, sessionTimeout, + requestTimeout, + encodingLimits, maxResponseMessageSize, maxPendingPublishRequests, identityProvider, @@ -231,13 +187,20 @@ public OpcUaClientConfig build() { static class OpcUaClientConfigImpl implements OpcUaClientConfig { - private final UaStackClientConfig stackClientConfig; + private final EndpointDescription endpoint; + private final KeyPair keyPair; + private final X509Certificate certificate; + private final X509Certificate[] certificateChain; + private final ClientCertificateValidator certificateValidator; private final LocalizedText applicationName; private final String applicationUri; private final String productUri; private final Supplier sessionName; private final String[] sessionLocaleIds; private final UInteger sessionTimeout; + + private final UInteger requestTimeout; + private final EncodingLimits encodingLimits; private final UInteger maxResponseMessageSize; private final UInteger maxPendingPublishRequests; private final IdentityProvider identityProvider; @@ -247,13 +210,19 @@ static class OpcUaClientConfigImpl implements OpcUaClientConfig { private final double subscriptionWatchdogMultiplier; OpcUaClientConfigImpl( - UaStackClientConfig stackClientConfig, + EndpointDescription endpoint, + KeyPair keyPair, + X509Certificate certificate, + X509Certificate[] certificateChain, + ClientCertificateValidator certificateValidator, LocalizedText applicationName, String applicationUri, String productUri, Supplier sessionName, String[] sessionLocaleIds, UInteger sessionTimeout, + UInteger requestTimeout, + EncodingLimits encodingLimits, UInteger maxResponseMessageSize, UInteger maxPendingPublishRequests, IdentityProvider identityProvider, @@ -262,14 +231,19 @@ static class OpcUaClientConfigImpl implements OpcUaClientConfig { UInteger keepAliveTimeout, double subscriptionWatchdogMultiplier ) { - - this.stackClientConfig = stackClientConfig; + this.endpoint = endpoint; + this.keyPair = keyPair; + this.certificate = certificate; + this.certificateChain = certificateChain; + this.certificateValidator = certificateValidator; this.applicationName = applicationName; this.applicationUri = applicationUri; this.productUri = productUri; this.sessionName = sessionName; this.sessionLocaleIds = sessionLocaleIds; this.sessionTimeout = sessionTimeout; + this.requestTimeout = requestTimeout; + this.encodingLimits = encodingLimits; this.maxResponseMessageSize = maxResponseMessageSize; this.maxPendingPublishRequests = maxPendingPublishRequests; this.identityProvider = identityProvider; @@ -279,6 +253,31 @@ static class OpcUaClientConfigImpl implements OpcUaClientConfig { this.subscriptionWatchdogMultiplier = subscriptionWatchdogMultiplier; } + @Override + public EndpointDescription getEndpoint() { + return endpoint; + } + + @Override + public Optional getKeyPair() { + return Optional.ofNullable(keyPair); + } + + @Override + public Optional getCertificate() { + return Optional.ofNullable(certificate); + } + + @Override + public Optional getCertificateChain() { + return Optional.ofNullable(certificateChain); + } + + @Override + public ClientCertificateValidator getCertificateValidator() { + return certificateValidator; + } + @Override public LocalizedText getApplicationName() { return applicationName; @@ -309,6 +308,16 @@ public UInteger getSessionTimeout() { return sessionTimeout; } + @Override + public UInteger getRequestTimeout() { + return requestTimeout; + } + + @Override + public EncodingLimits getEncodingLimits() { + return encodingLimits; + } + @Override public UInteger getMaxResponseMessageSize() { return maxResponseMessageSize; @@ -344,76 +353,6 @@ public double getSubscriptionWatchdogMultiplier() { return subscriptionWatchdogMultiplier; } - @Override - public EndpointDescription getEndpoint() { - return stackClientConfig.getEndpoint(); - } - - @Override - public Optional getKeyPair() { - return stackClientConfig.getKeyPair(); - } - - @Override - public Optional getCertificate() { - return stackClientConfig.getCertificate(); - } - - @Override - public Optional getCertificateChain() { - return stackClientConfig.getCertificateChain(); - } - - @Override - public ClientCertificateValidator getCertificateValidator() { - return stackClientConfig.getCertificateValidator(); - } - - @Override - public EncodingLimits getEncodingLimits() { - return stackClientConfig.getEncodingLimits(); - } - - @Override - public UInteger getChannelLifetime() { - return stackClientConfig.getChannelLifetime(); - } - - @Override - public ExecutorService getExecutor() { - return stackClientConfig.getExecutor(); - } - - @Override - public ScheduledExecutorService getScheduledExecutor() { - return stackClientConfig.getScheduledExecutor(); - } - - @Override - public NioEventLoopGroup getEventLoop() { - return stackClientConfig.getEventLoop(); - } - - @Override - public HashedWheelTimer getWheelTimer() { - return stackClientConfig.getWheelTimer(); - } - - @Override - public UInteger getConnectTimeout() { - return stackClientConfig.getConnectTimeout(); - } - - @Override - public UInteger getAcknowledgeTimeout() { - return stackClientConfig.getAcknowledgeTimeout(); - } - - @Override - public UInteger getRequestTimeout() { - return stackClientConfig.getRequestTimeout(); - } - } } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/identity/UsernameProvider.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/identity/UsernameProvider.java index c152078e9..64e4551c1 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/identity/UsernameProvider.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/api/identity/UsernameProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -22,11 +22,11 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator; import org.eclipse.milo.opcua.stack.core.Stack; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.channel.SecureChannel; +import org.eclipse.milo.opcua.stack.core.security.ClientCertificateValidator; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/ObjectTypeInitializer.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/ObjectTypeInitializer.java index 7a704ea47..dadf84007 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/ObjectTypeInitializer.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/ObjectTypeInitializer.java @@ -18,9 +18,11 @@ import org.eclipse.milo.opcua.sdk.client.model.objects.AlarmConditionTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.AlarmGroupTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.AlarmMetricsTypeNode; +import org.eclipse.milo.opcua.sdk.client.model.objects.AlarmSuppressionGroupTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.AliasNameCategoryTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.AliasNameTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.ApplicationCertificateTypeNode; +import org.eclipse.milo.opcua.sdk.client.model.objects.ApplicationConfigurationTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.AuditActivateSessionEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.AuditAddNodesEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.AuditAddReferencesEventTypeNode; @@ -83,6 +85,7 @@ import org.eclipse.milo.opcua.sdk.client.model.objects.CertificateGroupFolderTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.CertificateGroupTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.CertificateTypeNode; +import org.eclipse.milo.opcua.sdk.client.model.objects.CertificateUpdateRequestedAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.CertificateUpdatedAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.ChoiceStateTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.ConditionTypeNode; @@ -179,6 +182,7 @@ import org.eclipse.milo.opcua.sdk.client.model.objects.ProgramTransitionAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.ProgramTransitionEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.ProgressEventTypeNode; +import org.eclipse.milo.opcua.sdk.client.model.objects.ProvisionableDeviceTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.PubSubCapabilitiesTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.PubSubCommunicationFailureEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.PubSubConfigurationTypeNode; @@ -240,12 +244,14 @@ import org.eclipse.milo.opcua.sdk.client.model.objects.TemporaryFileTransferTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.TestingConditionClassTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.TrainingConditionClassTypeNode; +import org.eclipse.milo.opcua.sdk.client.model.objects.TransactionDiagnosticsTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.TransitionEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.TransitionTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.TransparentRedundancyTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.TripAlarmTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.TrustListOutOfDateAlarmTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.TrustListTypeNode; +import org.eclipse.milo.opcua.sdk.client.model.objects.TrustListUpdateRequestedAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.TrustListUpdatedAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.UadpDataSetReaderMessageTypeNode; import org.eclipse.milo.opcua.sdk.client.model.objects.UadpDataSetWriterMessageTypeNode; @@ -299,6 +305,12 @@ public static void initialize(NamespaceTable namespaceTable, AlarmGroupTypeNode.class, AlarmGroupTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=32064") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + AlarmSuppressionGroupTypeNode.class, + AlarmSuppressionGroupTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=13813") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -750,16 +762,16 @@ public static void initialize(NamespaceTable namespaceTable, AuditConditionOutOfServiceEventTypeNode::new ); objectTypeManager.registerObjectType( - NodeId.parse("i=12561") + NodeId.parse("i=32260") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), - TrustListUpdatedAuditEventTypeNode.class, - TrustListUpdatedAuditEventTypeNode::new + TrustListUpdateRequestedAuditEventTypeNode.class, + TrustListUpdateRequestedAuditEventTypeNode::new ); objectTypeManager.registerObjectType( - NodeId.parse("i=12620") + NodeId.parse("i=32306") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), - CertificateUpdatedAuditEventTypeNode.class, - CertificateUpdatedAuditEventTypeNode::new + CertificateUpdateRequestedAuditEventTypeNode.class, + CertificateUpdateRequestedAuditEventTypeNode::new ); objectTypeManager.registerObjectType( NodeId.parse("i=18011") @@ -791,6 +803,18 @@ public static void initialize(NamespaceTable namespaceTable, AuditClientUpdateMethodResultEventTypeNode.class, AuditClientUpdateMethodResultEventTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=12561") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + TrustListUpdatedAuditEventTypeNode.class, + TrustListUpdatedAuditEventTypeNode::new + ); + objectTypeManager.registerObjectType( + NodeId.parse("i=12620") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + CertificateUpdatedAuditEventTypeNode.class, + CertificateUpdatedAuditEventTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=2130") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -1385,12 +1409,24 @@ public static void initialize(NamespaceTable namespaceTable, UserCredentialCertificateTypeNode.class, UserCredentialCertificateTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=32286") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + TransactionDiagnosticsTypeNode.class, + TransactionDiagnosticsTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=12581") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), ServerConfigurationTypeNode.class, ServerConfigurationTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=25731") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + ApplicationConfigurationTypeNode.class, + ApplicationConfigurationTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=18001") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -1511,12 +1547,6 @@ public static void initialize(NamespaceTable namespaceTable, DatagramWriterGroupTransportTypeNode.class, DatagramWriterGroupTransportTypeNode::new ); - objectTypeManager.registerObjectType( - NodeId.parse("i=24016") - .reindex(namespaceTable, "http://opcfoundation.org/UA/"), - DatagramDataSetReaderTransportTypeNode.class, - DatagramDataSetReaderTransportTypeNode::new - ); objectTypeManager.registerObjectType( NodeId.parse("i=21136") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -1601,6 +1631,12 @@ public static void initialize(NamespaceTable namespaceTable, DataSetReaderTransportTypeNode.class, DataSetReaderTransportTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=24016") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + DatagramDataSetReaderTransportTypeNode.class, + DatagramDataSetReaderTransportTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=21142") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -1727,6 +1763,12 @@ public static void initialize(NamespaceTable namespaceTable, UserManagementTypeNode.class, UserManagementTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=26871") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + ProvisionableDeviceTypeNode.class, + ProvisionableDeviceTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=25221") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/VariableTypeInitializer.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/VariableTypeInitializer.java index f3ad3c2a6..8044e4ab3 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/VariableTypeInitializer.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/VariableTypeInitializer.java @@ -12,6 +12,7 @@ import org.eclipse.milo.opcua.sdk.client.VariableTypeManager; import org.eclipse.milo.opcua.sdk.client.model.variables.AlarmRateVariableTypeNode; +import org.eclipse.milo.opcua.sdk.client.model.variables.AlarmStateVariableTypeNode; import org.eclipse.milo.opcua.sdk.client.model.variables.AnalogItemTypeNode; import org.eclipse.milo.opcua.sdk.client.model.variables.AnalogUnitRangeTypeNode; import org.eclipse.milo.opcua.sdk.client.model.variables.AnalogUnitTypeNode; @@ -47,6 +48,7 @@ import org.eclipse.milo.opcua.sdk.client.model.variables.PropertyTypeNode; import org.eclipse.milo.opcua.sdk.client.model.variables.PubSubDiagnosticsCounterTypeNode; import org.eclipse.milo.opcua.sdk.client.model.variables.RationalNumberTypeNode; +import org.eclipse.milo.opcua.sdk.client.model.variables.ReferenceDescriptionVariableTypeNode; import org.eclipse.milo.opcua.sdk.client.model.variables.SamplingIntervalDiagnosticsArrayTypeNode; import org.eclipse.milo.opcua.sdk.client.model.variables.SamplingIntervalDiagnosticsTypeNode; import org.eclipse.milo.opcua.sdk.client.model.variables.SelectionListTypeNode; @@ -406,6 +408,12 @@ public static void initialize(NamespaceTable namespaceTable, AlarmRateVariableTypeNode.class, AlarmRateVariableTypeNode::new ); + variableTypeManager.registerVariableType( + NodeId.parse("i=32244") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + AlarmStateVariableTypeNode.class, + AlarmStateVariableTypeNode::new + ); variableTypeManager.registerVariableType( NodeId.parse("i=2380") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -424,6 +432,12 @@ public static void initialize(NamespaceTable namespaceTable, PubSubDiagnosticsCounterTypeNode.class, PubSubDiagnosticsCounterTypeNode::new ); + variableTypeManager.registerVariableType( + NodeId.parse("i=32657") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + ReferenceDescriptionVariableTypeNode.class, + ReferenceDescriptionVariableTypeNode::new + ); variableTypeManager.registerVariableType( NodeId.parse("i=68") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AggregateConfigurationType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AggregateConfigurationType.java index a353aaa53..d9a1e45a6 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AggregateConfigurationType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AggregateConfigurationType.java @@ -19,6 +19,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part13/4.2.1/#4.2.1.2 + */ public interface AggregateConfigurationType extends BaseObjectType { QualifiedProperty TREAT_UNCERTAIN_AS_BAD = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AggregateFunctionType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AggregateFunctionType.java index c1e116863..49edd6927 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AggregateFunctionType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AggregateFunctionType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part5/6.8 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part13/4.2.2/#4.2.2.2 */ public interface AggregateFunctionType extends BaseObjectType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmMetricsType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmMetricsType.java index e6ef0935f..968706f0c 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmMetricsType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmMetricsType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/8.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/9.2 */ public interface AlarmMetricsType extends BaseObjectType { /** diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmSuppressionGroupType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmSuppressionGroupType.java new file mode 100644 index 000000000..46d600924 --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmSuppressionGroupType.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.4 + */ +public interface AlarmSuppressionGroupType extends AlarmGroupType { +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmSuppressionGroupTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmSuppressionGroupTypeNode.java new file mode 100644 index 000000000..83eb1d52d --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AlarmSuppressionGroupTypeNode.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class AlarmSuppressionGroupTypeNode extends AlarmGroupTypeNode implements AlarmSuppressionGroupType { + public AlarmSuppressionGroupTypeNode(OpcUaClient client, NodeId nodeId, NodeClass nodeClass, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationCertificateType.java index 7be193620..5293ce84e 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationCertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.2 + */ public interface ApplicationCertificateType extends CertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationConfigurationType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationConfigurationType.java new file mode 100644 index 000000000..8d5e5d81f --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationConfigurationType.java @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.client.model.variables.PropertyType; +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part21/9.3.6 + */ +public interface ApplicationConfigurationType extends ServerConfigurationType { + QualifiedProperty APPLICATION_URI = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ApplicationUri", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23751"), + -1, + String.class + ); + + QualifiedProperty PRODUCT_URI = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ProductUri", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23751"), + -1, + String.class + ); + + QualifiedProperty APPLICATION_TYPE = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ApplicationType", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=307"), + -1, + ApplicationType.class + ); + + QualifiedProperty ENABLED = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "Enabled", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + + /** + * Get the local value of the ApplicationUri Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ApplicationUri Node. + * @throws UaException if an error occurs creating or getting the ApplicationUri Node. + */ + String getApplicationUri() throws UaException; + + /** + * Set the local value of the ApplicationUri Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ApplicationUri Node. + * @throws UaException if an error occurs creating or getting the ApplicationUri Node. + */ + void setApplicationUri(String value) throws UaException; + + /** + * Read the value of the ApplicationUri Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link String} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + String readApplicationUri() throws UaException; + + /** + * Write a new value for the ApplicationUri Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link String} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeApplicationUri(String value) throws UaException; + + /** + * An asynchronous implementation of {@link #readApplicationUri}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readApplicationUriAsync(); + + /** + * An asynchronous implementation of {@link #writeApplicationUri}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeApplicationUriAsync(String value); + + /** + * Get the ApplicationUri {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ApplicationUri {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getApplicationUriNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getApplicationUriNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getApplicationUriNodeAsync(); + + /** + * Get the local value of the ProductUri Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ProductUri Node. + * @throws UaException if an error occurs creating or getting the ProductUri Node. + */ + String getProductUri() throws UaException; + + /** + * Set the local value of the ProductUri Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ProductUri Node. + * @throws UaException if an error occurs creating or getting the ProductUri Node. + */ + void setProductUri(String value) throws UaException; + + /** + * Read the value of the ProductUri Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link String} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + String readProductUri() throws UaException; + + /** + * Write a new value for the ProductUri Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link String} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeProductUri(String value) throws UaException; + + /** + * An asynchronous implementation of {@link #readProductUri}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readProductUriAsync(); + + /** + * An asynchronous implementation of {@link #writeProductUri}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeProductUriAsync(String value); + + /** + * Get the ProductUri {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ProductUri {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getProductUriNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getProductUriNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getProductUriNodeAsync(); + + /** + * Get the local value of the ApplicationType Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ApplicationType Node. + * @throws UaException if an error occurs creating or getting the ApplicationType Node. + */ + ApplicationType getApplicationType() throws UaException; + + /** + * Set the local value of the ApplicationType Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ApplicationType Node. + * @throws UaException if an error occurs creating or getting the ApplicationType Node. + */ + void setApplicationType(ApplicationType value) throws UaException; + + /** + * Read the value of the ApplicationType Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link ApplicationType} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + ApplicationType readApplicationType() throws UaException; + + /** + * Write a new value for the ApplicationType Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link ApplicationType} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeApplicationType(ApplicationType value) throws UaException; + + /** + * An asynchronous implementation of {@link #readApplicationType}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readApplicationTypeAsync(); + + /** + * An asynchronous implementation of {@link #writeApplicationType}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeApplicationTypeAsync(ApplicationType value); + + /** + * Get the ApplicationType {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ApplicationType {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getApplicationTypeNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getApplicationTypeNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getApplicationTypeNodeAsync(); + + /** + * Get the local value of the Enabled Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the Enabled Node. + * @throws UaException if an error occurs creating or getting the Enabled Node. + */ + Boolean getEnabled() throws UaException; + + /** + * Set the local value of the Enabled Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the Enabled Node. + * @throws UaException if an error occurs creating or getting the Enabled Node. + */ + void setEnabled(Boolean value) throws UaException; + + /** + * Read the value of the Enabled Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link Boolean} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + Boolean readEnabled() throws UaException; + + /** + * Write a new value for the Enabled Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link Boolean} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeEnabled(Boolean value) throws UaException; + + /** + * An asynchronous implementation of {@link #readEnabled}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readEnabledAsync(); + + /** + * An asynchronous implementation of {@link #writeEnabled}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeEnabledAsync(Boolean value); + + /** + * Get the Enabled {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the Enabled {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getEnabledNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getEnabledNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getEnabledNodeAsync(); +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationConfigurationTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationConfigurationTypeNode.java new file mode 100644 index 000000000..40c24623e --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ApplicationConfigurationTypeNode.java @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; +import org.eclipse.milo.opcua.sdk.client.model.variables.PropertyTypeNode; +import org.eclipse.milo.opcua.sdk.client.nodes.UaNode; +import org.eclipse.milo.opcua.stack.core.AttributeId; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; +import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class ApplicationConfigurationTypeNode extends ServerConfigurationTypeNode implements ApplicationConfigurationType { + public ApplicationConfigurationTypeNode(OpcUaClient client, NodeId nodeId, NodeClass nodeClass, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } + + @Override + public String getApplicationUri() throws UaException { + PropertyTypeNode node = getApplicationUriNode(); + return (String) node.getValue().getValue().getValue(); + } + + @Override + public void setApplicationUri(String value) throws UaException { + PropertyTypeNode node = getApplicationUriNode(); + node.setValue(new Variant(value)); + } + + @Override + public String readApplicationUri() throws UaException { + try { + return readApplicationUriAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeApplicationUri(String value) throws UaException { + try { + writeApplicationUriAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readApplicationUriAsync() { + return getApplicationUriNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (String) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeApplicationUriAsync(String applicationUri) { + DataValue value = DataValue.valueOnly(new Variant(applicationUri)); + return getApplicationUriNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getApplicationUriNode() throws UaException { + try { + return getApplicationUriNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getApplicationUriNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ApplicationUri", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public String getProductUri() throws UaException { + PropertyTypeNode node = getProductUriNode(); + return (String) node.getValue().getValue().getValue(); + } + + @Override + public void setProductUri(String value) throws UaException { + PropertyTypeNode node = getProductUriNode(); + node.setValue(new Variant(value)); + } + + @Override + public String readProductUri() throws UaException { + try { + return readProductUriAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeProductUri(String value) throws UaException { + try { + writeProductUriAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readProductUriAsync() { + return getProductUriNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (String) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeProductUriAsync(String productUri) { + DataValue value = DataValue.valueOnly(new Variant(productUri)); + return getProductUriNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getProductUriNode() throws UaException { + try { + return getProductUriNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getProductUriNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ProductUri", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public ApplicationType getApplicationType() throws UaException { + PropertyTypeNode node = getApplicationTypeNode(); + Object value = node.getValue().getValue().getValue(); + + if (value instanceof Integer) { + return ApplicationType.from((Integer) value); + } else if (value instanceof ApplicationType) { + return (ApplicationType) value; + } else { + return null; + } + } + + @Override + public void setApplicationType(ApplicationType value) throws UaException { + PropertyTypeNode node = getApplicationTypeNode(); + node.setValue(new Variant(value)); + } + + @Override + public ApplicationType readApplicationType() throws UaException { + try { + return readApplicationTypeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeApplicationType(ApplicationType value) throws UaException { + try { + writeApplicationTypeAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readApplicationTypeAsync() { + return getApplicationTypeNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> { + Object value = v.getValue().getValue(); + if (value instanceof Integer) { + return ApplicationType.from((Integer) value); + } else { + return null; + } + }); + } + + @Override + public CompletableFuture writeApplicationTypeAsync(ApplicationType applicationType) { + DataValue value = DataValue.valueOnly(new Variant(applicationType)); + return getApplicationTypeNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getApplicationTypeNode() throws UaException { + try { + return getApplicationTypeNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getApplicationTypeNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ApplicationType", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public Boolean getEnabled() throws UaException { + PropertyTypeNode node = getEnabledNode(); + return (Boolean) node.getValue().getValue().getValue(); + } + + @Override + public void setEnabled(Boolean value) throws UaException { + PropertyTypeNode node = getEnabledNode(); + node.setValue(new Variant(value)); + } + + @Override + public Boolean readEnabled() throws UaException { + try { + return readEnabledAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeEnabled(Boolean value) throws UaException { + try { + writeEnabledAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readEnabledAsync() { + return getEnabledNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (Boolean) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeEnabledAsync(Boolean enabled) { + DataValue value = DataValue.valueOnly(new Variant(enabled)); + return getEnabledNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getEnabledNode() throws UaException { + try { + return getEnabledNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getEnabledNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "Enabled", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryAnnotationUpdateEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryAnnotationUpdateEventType.java index 1f919bfbe..040f134d0 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryAnnotationUpdateEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryAnnotationUpdateEventType.java @@ -21,7 +21,7 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.PerformUpdateType; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.4 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.4 */ public interface AuditHistoryAnnotationUpdateEventType extends AuditHistoryUpdateEventType { QualifiedProperty PERFORM_INSERT_REPLACE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryAtTimeDeleteEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryAtTimeDeleteEventType.java index 9644d2137..44082e9ae 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryAtTimeDeleteEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryAtTimeDeleteEventType.java @@ -21,7 +21,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.7 */ public interface AuditHistoryAtTimeDeleteEventType extends AuditHistoryDeleteEventType { QualifiedProperty REQ_TIMES = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryDeleteEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryDeleteEventType.java index 95586af00..57d1583bb 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryDeleteEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryDeleteEventType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.5 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.5 */ public interface AuditHistoryDeleteEventType extends AuditHistoryUpdateEventType { QualifiedProperty UPDATED_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryEventDeleteEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryEventDeleteEventType.java index 265b7531e..068dd0e19 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryEventDeleteEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryEventDeleteEventType.java @@ -21,7 +21,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.HistoryEventFieldList; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.8 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.8 */ public interface AuditHistoryEventDeleteEventType extends AuditHistoryDeleteEventType { QualifiedProperty EVENT_IDS = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryEventUpdateEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryEventUpdateEventType.java index 505372ede..9bd681317 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryEventUpdateEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryEventUpdateEventType.java @@ -23,7 +23,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.HistoryEventFieldList; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.2 */ public interface AuditHistoryEventUpdateEventType extends AuditHistoryUpdateEventType { QualifiedProperty UPDATED_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryRawModifyDeleteEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryRawModifyDeleteEventType.java index b228883b7..c5b69dcf8 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryRawModifyDeleteEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryRawModifyDeleteEventType.java @@ -21,7 +21,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.6 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.6 */ public interface AuditHistoryRawModifyDeleteEventType extends AuditHistoryDeleteEventType { QualifiedProperty IS_DELETE_MODIFIED = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryValueUpdateEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryValueUpdateEventType.java index 36cea6107..5fc991834 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryValueUpdateEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuditHistoryValueUpdateEventType.java @@ -22,7 +22,7 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.PerformUpdateType; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.3 */ public interface AuditHistoryValueUpdateEventType extends AuditHistoryUpdateEventType { QualifiedProperty UPDATED_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuthorizationServiceConfigurationType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuthorizationServiceConfigurationType.java index a72fda8d5..95724969f 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuthorizationServiceConfigurationType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuthorizationServiceConfigurationType.java @@ -19,6 +19,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/9.7.4 + */ public interface AuthorizationServiceConfigurationType extends BaseObjectType { QualifiedProperty SERVICE_URI = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuthorizationServicesConfigurationFolderType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuthorizationServicesConfigurationFolderType.java index 8ab2abffd..ec9c63f44 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuthorizationServicesConfigurationFolderType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/AuthorizationServicesConfigurationFolderType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/9.7.2 + */ public interface AuthorizationServicesConfigurationFolderType extends FolderType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/BaseEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/BaseEventType.java index c4a087427..b4beb5a70 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/BaseEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/BaseEventType.java @@ -100,6 +100,38 @@ public interface BaseEventType extends BaseObjectType { UShort.class ); + QualifiedProperty CONDITION_CLASS_ID = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConditionClassId", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + -1, + NodeId.class + ); + + QualifiedProperty CONDITION_CLASS_NAME = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConditionClassName", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=21"), + -1, + LocalizedText.class + ); + + QualifiedProperty CONDITION_SUB_CLASS_ID = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConditionSubClassId", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + 1, + NodeId[].class + ); + + QualifiedProperty CONDITION_SUB_CLASS_NAME = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConditionSubClassName", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=21"), + 1, + LocalizedText[].class + ); + /** * Get the local value of the EventId Node. *

@@ -756,4 +788,296 @@ public interface BaseEventType extends BaseObjectType { * getting the Node. */ CompletableFuture getSeverityNodeAsync(); + + /** + * Get the local value of the ConditionClassId Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ConditionClassId Node. + * @throws UaException if an error occurs creating or getting the ConditionClassId Node. + */ + NodeId getConditionClassId() throws UaException; + + /** + * Set the local value of the ConditionClassId Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ConditionClassId Node. + * @throws UaException if an error occurs creating or getting the ConditionClassId Node. + */ + void setConditionClassId(NodeId value) throws UaException; + + /** + * Read the value of the ConditionClassId Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link NodeId} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + NodeId readConditionClassId() throws UaException; + + /** + * Write a new value for the ConditionClassId Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link NodeId} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeConditionClassId(NodeId value) throws UaException; + + /** + * An asynchronous implementation of {@link #readConditionClassId}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readConditionClassIdAsync(); + + /** + * An asynchronous implementation of {@link #writeConditionClassId}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeConditionClassIdAsync(NodeId value); + + /** + * Get the ConditionClassId {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ConditionClassId {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getConditionClassIdNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getConditionClassIdNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getConditionClassIdNodeAsync(); + + /** + * Get the local value of the ConditionClassName Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ConditionClassName Node. + * @throws UaException if an error occurs creating or getting the ConditionClassName Node. + */ + LocalizedText getConditionClassName() throws UaException; + + /** + * Set the local value of the ConditionClassName Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ConditionClassName Node. + * @throws UaException if an error occurs creating or getting the ConditionClassName Node. + */ + void setConditionClassName(LocalizedText value) throws UaException; + + /** + * Read the value of the ConditionClassName Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link LocalizedText} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + LocalizedText readConditionClassName() throws UaException; + + /** + * Write a new value for the ConditionClassName Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link LocalizedText} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeConditionClassName(LocalizedText value) throws UaException; + + /** + * An asynchronous implementation of {@link #readConditionClassName}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readConditionClassNameAsync(); + + /** + * An asynchronous implementation of {@link #writeConditionClassName}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeConditionClassNameAsync(LocalizedText value); + + /** + * Get the ConditionClassName {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ConditionClassName {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getConditionClassNameNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getConditionClassNameNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getConditionClassNameNodeAsync(); + + /** + * Get the local value of the ConditionSubClassId Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ConditionSubClassId Node. + * @throws UaException if an error occurs creating or getting the ConditionSubClassId Node. + */ + NodeId[] getConditionSubClassId() throws UaException; + + /** + * Set the local value of the ConditionSubClassId Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ConditionSubClassId Node. + * @throws UaException if an error occurs creating or getting the ConditionSubClassId Node. + */ + void setConditionSubClassId(NodeId[] value) throws UaException; + + /** + * Read the value of the ConditionSubClassId Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link NodeId[]} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + NodeId[] readConditionSubClassId() throws UaException; + + /** + * Write a new value for the ConditionSubClassId Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link NodeId[]} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeConditionSubClassId(NodeId[] value) throws UaException; + + /** + * An asynchronous implementation of {@link #readConditionSubClassId}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readConditionSubClassIdAsync(); + + /** + * An asynchronous implementation of {@link #writeConditionSubClassId}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeConditionSubClassIdAsync(NodeId[] value); + + /** + * Get the ConditionSubClassId {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ConditionSubClassId {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getConditionSubClassIdNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getConditionSubClassIdNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getConditionSubClassIdNodeAsync(); + + /** + * Get the local value of the ConditionSubClassName Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ConditionSubClassName Node. + * @throws UaException if an error occurs creating or getting the ConditionSubClassName Node. + */ + LocalizedText[] getConditionSubClassName() throws UaException; + + /** + * Set the local value of the ConditionSubClassName Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ConditionSubClassName Node. + * @throws UaException if an error occurs creating or getting the ConditionSubClassName Node. + */ + void setConditionSubClassName(LocalizedText[] value) throws UaException; + + /** + * Read the value of the ConditionSubClassName Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link LocalizedText[]} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + LocalizedText[] readConditionSubClassName() throws UaException; + + /** + * Write a new value for the ConditionSubClassName Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link LocalizedText[]} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeConditionSubClassName(LocalizedText[] value) throws UaException; + + /** + * An asynchronous implementation of {@link #readConditionSubClassName}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readConditionSubClassNameAsync(); + + /** + * An asynchronous implementation of {@link #writeConditionSubClassName}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeConditionSubClassNameAsync(LocalizedText[] value); + + /** + * Get the ConditionSubClassName {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ConditionSubClassName {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getConditionSubClassNameNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getConditionSubClassNameNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getConditionSubClassNameNodeAsync(); } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/BaseEventTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/BaseEventTypeNode.java index e4ec7ca30..de5b19b61 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/BaseEventTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/BaseEventTypeNode.java @@ -623,4 +623,262 @@ public CompletableFuture getSeverityNodeAsync() { ); return future.thenApply(node -> (PropertyTypeNode) node); } + + @Override + public NodeId getConditionClassId() throws UaException { + PropertyTypeNode node = getConditionClassIdNode(); + return (NodeId) node.getValue().getValue().getValue(); + } + + @Override + public void setConditionClassId(NodeId value) throws UaException { + PropertyTypeNode node = getConditionClassIdNode(); + node.setValue(new Variant(value)); + } + + @Override + public NodeId readConditionClassId() throws UaException { + try { + return readConditionClassIdAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeConditionClassId(NodeId value) throws UaException { + try { + writeConditionClassIdAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readConditionClassIdAsync() { + return getConditionClassIdNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (NodeId) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeConditionClassIdAsync(NodeId conditionClassId) { + DataValue value = DataValue.valueOnly(new Variant(conditionClassId)); + return getConditionClassIdNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getConditionClassIdNode() throws UaException { + try { + return getConditionClassIdNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getConditionClassIdNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ConditionClassId", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public LocalizedText getConditionClassName() throws UaException { + PropertyTypeNode node = getConditionClassNameNode(); + return (LocalizedText) node.getValue().getValue().getValue(); + } + + @Override + public void setConditionClassName(LocalizedText value) throws UaException { + PropertyTypeNode node = getConditionClassNameNode(); + node.setValue(new Variant(value)); + } + + @Override + public LocalizedText readConditionClassName() throws UaException { + try { + return readConditionClassNameAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeConditionClassName(LocalizedText value) throws UaException { + try { + writeConditionClassNameAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readConditionClassNameAsync() { + return getConditionClassNameNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (LocalizedText) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeConditionClassNameAsync( + LocalizedText conditionClassName) { + DataValue value = DataValue.valueOnly(new Variant(conditionClassName)); + return getConditionClassNameNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getConditionClassNameNode() throws UaException { + try { + return getConditionClassNameNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getConditionClassNameNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ConditionClassName", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public NodeId[] getConditionSubClassId() throws UaException { + PropertyTypeNode node = getConditionSubClassIdNode(); + return (NodeId[]) node.getValue().getValue().getValue(); + } + + @Override + public void setConditionSubClassId(NodeId[] value) throws UaException { + PropertyTypeNode node = getConditionSubClassIdNode(); + node.setValue(new Variant(value)); + } + + @Override + public NodeId[] readConditionSubClassId() throws UaException { + try { + return readConditionSubClassIdAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeConditionSubClassId(NodeId[] value) throws UaException { + try { + writeConditionSubClassIdAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readConditionSubClassIdAsync() { + return getConditionSubClassIdNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (NodeId[]) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeConditionSubClassIdAsync(NodeId[] conditionSubClassId) { + DataValue value = DataValue.valueOnly(new Variant(conditionSubClassId)); + return getConditionSubClassIdNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getConditionSubClassIdNode() throws UaException { + try { + return getConditionSubClassIdNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getConditionSubClassIdNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ConditionSubClassId", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public LocalizedText[] getConditionSubClassName() throws UaException { + PropertyTypeNode node = getConditionSubClassNameNode(); + return (LocalizedText[]) node.getValue().getValue().getValue(); + } + + @Override + public void setConditionSubClassName(LocalizedText[] value) throws UaException { + PropertyTypeNode node = getConditionSubClassNameNode(); + node.setValue(new Variant(value)); + } + + @Override + public LocalizedText[] readConditionSubClassName() throws UaException { + try { + return readConditionSubClassNameAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeConditionSubClassName(LocalizedText[] value) throws UaException { + try { + writeConditionSubClassNameAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readConditionSubClassNameAsync() { + return getConditionSubClassNameNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (LocalizedText[]) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeConditionSubClassNameAsync( + LocalizedText[] conditionSubClassName) { + DataValue value = DataValue.valueOnly(new Variant(conditionSubClassName)); + return getConditionSubClassNameNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getConditionSubClassNameNode() throws UaException { + try { + return getConditionSubClassNameNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getConditionSubClassNameNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ConditionSubClassName", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateExpirationAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateExpirationAlarmType.java index 88b676fff..367c5ae05 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateExpirationAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateExpirationAlarmType.java @@ -22,7 +22,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.7 */ public interface CertificateExpirationAlarmType extends SystemOffNormalAlarmType { QualifiedProperty EXPIRATION_DATE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupFolderType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupFolderType.java index 407314789..c64a439fa 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupFolderType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupFolderType.java @@ -14,6 +14,9 @@ import org.eclipse.milo.opcua.stack.core.UaException; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.3/#7.8.3.3 + */ public interface CertificateGroupFolderType extends FolderType { /** * Get the DefaultApplicationGroup {@link CertificateGroupType} Node, or {@code null} if it does not exist. diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupFolderTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupFolderTypeNode.java index 29ea1d396..72dba0d94 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupFolderTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupFolderTypeNode.java @@ -51,7 +51,7 @@ public CompletableFuture getDefaultApplicati CompletableFuture future = getMemberNodeAsync( "http://opcfoundation.org/UA/", "DefaultApplicationGroup", - ExpandedNodeId.parse("ns=0;i=35"), + ExpandedNodeId.parse("ns=0;i=47"), false ); return future.thenApply(node -> (CertificateGroupTypeNode) node); @@ -71,7 +71,7 @@ public CompletableFuture getDefaultHttpsGrou CompletableFuture future = getMemberNodeAsync( "http://opcfoundation.org/UA/", "DefaultHttpsGroup", - ExpandedNodeId.parse("ns=0;i=35"), + ExpandedNodeId.parse("ns=0;i=47"), false ); return future.thenApply(node -> (CertificateGroupTypeNode) node); @@ -91,7 +91,7 @@ public CompletableFuture getDefaultUserToken CompletableFuture future = getMemberNodeAsync( "http://opcfoundation.org/UA/", "DefaultUserTokenGroup", - ExpandedNodeId.parse("ns=0;i=35"), + ExpandedNodeId.parse("ns=0;i=47"), false ); return future.thenApply(node -> (CertificateGroupTypeNode) node); diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupType.java index 43d640d1c..98b1c63f9 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateGroupType.java @@ -19,6 +19,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.3/#7.8.3.1 + */ public interface CertificateGroupType extends BaseObjectType { QualifiedProperty CERTIFICATE_TYPES = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateType.java index 7a07015ba..bb77799fc 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.1 + */ public interface CertificateType extends BaseObjectType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdateRequestedAuditEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdateRequestedAuditEventType.java new file mode 100644 index 000000000..223c0d18f --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdateRequestedAuditEventType.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.10.13 + */ +public interface CertificateUpdateRequestedAuditEventType extends AuditUpdateMethodEventType { +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdateRequestedAuditEventTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdateRequestedAuditEventTypeNode.java new file mode 100644 index 000000000..fba52a67c --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdateRequestedAuditEventTypeNode.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class CertificateUpdateRequestedAuditEventTypeNode extends AuditUpdateMethodEventTypeNode implements CertificateUpdateRequestedAuditEventType { + public CertificateUpdateRequestedAuditEventTypeNode(OpcUaClient client, NodeId nodeId, + NodeClass nodeClass, QualifiedName browseName, LocalizedText displayName, + LocalizedText description, UInteger writeMask, UInteger userWriteMask, + RolePermissionType[] rolePermissions, RolePermissionType[] userRolePermissions, + AccessRestrictionType accessRestrictions, UByte eventNotifier) { + super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdatedAuditEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdatedAuditEventType.java index 60515c76f..025c3a7be 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdatedAuditEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdatedAuditEventType.java @@ -19,7 +19,10 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; -public interface CertificateUpdatedAuditEventType extends AuditUpdateMethodEventType { +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.10.14 + */ +public interface CertificateUpdatedAuditEventType extends AuditEventType { QualifiedProperty CERTIFICATE_GROUP = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "CertificateGroup", diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdatedAuditEventTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdatedAuditEventTypeNode.java index eb1b7f38b..f81a3b743 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdatedAuditEventTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/CertificateUpdatedAuditEventTypeNode.java @@ -32,7 +32,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; -public class CertificateUpdatedAuditEventTypeNode extends AuditUpdateMethodEventTypeNode implements CertificateUpdatedAuditEventType { +public class CertificateUpdatedAuditEventTypeNode extends AuditEventTypeNode implements CertificateUpdatedAuditEventType { public CertificateUpdatedAuditEventTypeNode(OpcUaClient client, NodeId nodeId, NodeClass nodeClass, QualifiedName browseName, LocalizedText displayName, LocalizedText description, UInteger writeMask, UInteger userWriteMask, diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ConditionType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ConditionType.java index 3ff909ada..bd125e342 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ConditionType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ConditionType.java @@ -43,22 +43,6 @@ public interface ConditionType extends BaseEventType { LocalizedText.class ); - QualifiedProperty CONDITION_SUB_CLASS_ID = new QualifiedProperty<>( - "http://opcfoundation.org/UA/", - "ConditionSubClassId", - ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), - 1, - NodeId[].class - ); - - QualifiedProperty CONDITION_SUB_CLASS_NAME = new QualifiedProperty<>( - "http://opcfoundation.org/UA/", - "ConditionSubClassName", - ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=21"), - 1, - LocalizedText[].class - ); - QualifiedProperty CONDITION_NAME = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "ConditionName", @@ -83,6 +67,14 @@ public interface ConditionType extends BaseEventType { Boolean.class ); + QualifiedProperty SUPPORTS_FILTERED_RETAIN = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "SupportsFilteredRetain", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + QualifiedProperty CLIENT_USER_ID = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "ClientUserId", @@ -237,152 +229,6 @@ public interface ConditionType extends BaseEventType { */ CompletableFuture getConditionClassNameNodeAsync(); - /** - * Get the local value of the ConditionSubClassId Node. - *

- * The returned value is the last seen; it is not read live from the server. - * - * @return the local value of the ConditionSubClassId Node. - * @throws UaException if an error occurs creating or getting the ConditionSubClassId Node. - */ - NodeId[] getConditionSubClassId() throws UaException; - - /** - * Set the local value of the ConditionSubClassId Node. - *

- * The value is only updated locally; it is not written to the server. - * - * @param value the local value to set for the ConditionSubClassId Node. - * @throws UaException if an error occurs creating or getting the ConditionSubClassId Node. - */ - void setConditionSubClassId(NodeId[] value) throws UaException; - - /** - * Read the value of the ConditionSubClassId Node from the server and update the local value if - * the operation succeeds. - * - * @return the {@link NodeId[]} value read from the server. - * @throws UaException if a service- or operation-level error occurs. - */ - NodeId[] readConditionSubClassId() throws UaException; - - /** - * Write a new value for the ConditionSubClassId Node to the server and update the local value if - * the operation succeeds. - * - * @param value the {@link NodeId[]} value to write to the server. - * @throws UaException if a service- or operation-level error occurs. - */ - void writeConditionSubClassId(NodeId[] value) throws UaException; - - /** - * An asynchronous implementation of {@link #readConditionSubClassId}. - * - * @return a CompletableFuture that completes successfully with the value or completes - * exceptionally if an operation- or service-level error occurs. - */ - CompletableFuture readConditionSubClassIdAsync(); - - /** - * An asynchronous implementation of {@link #writeConditionSubClassId}. - * - * @return a CompletableFuture that completes successfully with the operation result or - * completes exceptionally if a service-level error occurs. - */ - CompletableFuture writeConditionSubClassIdAsync(NodeId[] value); - - /** - * Get the ConditionSubClassId {@link PropertyType} Node, or {@code null} if it does not exist. - *

- * The Node is created when first accessed and cached for subsequent calls. - * - * @return the ConditionSubClassId {@link PropertyType} Node, or {@code null} if it does not exist. - * @throws UaException if an error occurs creating or getting the Node. - */ - PropertyType getConditionSubClassIdNode() throws UaException; - - /** - * Asynchronous implementation of {@link #getConditionSubClassIdNode()}. - * - * @return a CompletableFuture that completes successfully with the - * PropertyType Node or completes exceptionally if an error occurs creating or - * getting the Node. - */ - CompletableFuture getConditionSubClassIdNodeAsync(); - - /** - * Get the local value of the ConditionSubClassName Node. - *

- * The returned value is the last seen; it is not read live from the server. - * - * @return the local value of the ConditionSubClassName Node. - * @throws UaException if an error occurs creating or getting the ConditionSubClassName Node. - */ - LocalizedText[] getConditionSubClassName() throws UaException; - - /** - * Set the local value of the ConditionSubClassName Node. - *

- * The value is only updated locally; it is not written to the server. - * - * @param value the local value to set for the ConditionSubClassName Node. - * @throws UaException if an error occurs creating or getting the ConditionSubClassName Node. - */ - void setConditionSubClassName(LocalizedText[] value) throws UaException; - - /** - * Read the value of the ConditionSubClassName Node from the server and update the local value if - * the operation succeeds. - * - * @return the {@link LocalizedText[]} value read from the server. - * @throws UaException if a service- or operation-level error occurs. - */ - LocalizedText[] readConditionSubClassName() throws UaException; - - /** - * Write a new value for the ConditionSubClassName Node to the server and update the local value if - * the operation succeeds. - * - * @param value the {@link LocalizedText[]} value to write to the server. - * @throws UaException if a service- or operation-level error occurs. - */ - void writeConditionSubClassName(LocalizedText[] value) throws UaException; - - /** - * An asynchronous implementation of {@link #readConditionSubClassName}. - * - * @return a CompletableFuture that completes successfully with the value or completes - * exceptionally if an operation- or service-level error occurs. - */ - CompletableFuture readConditionSubClassNameAsync(); - - /** - * An asynchronous implementation of {@link #writeConditionSubClassName}. - * - * @return a CompletableFuture that completes successfully with the operation result or - * completes exceptionally if a service-level error occurs. - */ - CompletableFuture writeConditionSubClassNameAsync(LocalizedText[] value); - - /** - * Get the ConditionSubClassName {@link PropertyType} Node, or {@code null} if it does not exist. - *

- * The Node is created when first accessed and cached for subsequent calls. - * - * @return the ConditionSubClassName {@link PropertyType} Node, or {@code null} if it does not exist. - * @throws UaException if an error occurs creating or getting the Node. - */ - PropertyType getConditionSubClassNameNode() throws UaException; - - /** - * Asynchronous implementation of {@link #getConditionSubClassNameNode()}. - * - * @return a CompletableFuture that completes successfully with the - * PropertyType Node or completes exceptionally if an error occurs creating or - * getting the Node. - */ - CompletableFuture getConditionSubClassNameNodeAsync(); - /** * Get the local value of the ConditionName Node. *

@@ -602,6 +448,79 @@ public interface ConditionType extends BaseEventType { */ CompletableFuture getRetainNodeAsync(); + /** + * Get the local value of the SupportsFilteredRetain Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the SupportsFilteredRetain Node. + * @throws UaException if an error occurs creating or getting the SupportsFilteredRetain Node. + */ + Boolean getSupportsFilteredRetain() throws UaException; + + /** + * Set the local value of the SupportsFilteredRetain Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the SupportsFilteredRetain Node. + * @throws UaException if an error occurs creating or getting the SupportsFilteredRetain Node. + */ + void setSupportsFilteredRetain(Boolean value) throws UaException; + + /** + * Read the value of the SupportsFilteredRetain Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link Boolean} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + Boolean readSupportsFilteredRetain() throws UaException; + + /** + * Write a new value for the SupportsFilteredRetain Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link Boolean} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeSupportsFilteredRetain(Boolean value) throws UaException; + + /** + * An asynchronous implementation of {@link #readSupportsFilteredRetain}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readSupportsFilteredRetainAsync(); + + /** + * An asynchronous implementation of {@link #writeSupportsFilteredRetain}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeSupportsFilteredRetainAsync(Boolean value); + + /** + * Get the SupportsFilteredRetain {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the SupportsFilteredRetain {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getSupportsFilteredRetainNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getSupportsFilteredRetainNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getSupportsFilteredRetainNodeAsync(); + /** * Get the local value of the ClientUserId Node. *

diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ConditionTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ConditionTypeNode.java index 1be3e1840..3e9238887 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ConditionTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ConditionTypeNode.java @@ -173,135 +173,6 @@ public CompletableFuture getConditionClassNameNodeAs return future.thenApply(node -> (PropertyTypeNode) node); } - @Override - public NodeId[] getConditionSubClassId() throws UaException { - PropertyTypeNode node = getConditionSubClassIdNode(); - return (NodeId[]) node.getValue().getValue().getValue(); - } - - @Override - public void setConditionSubClassId(NodeId[] value) throws UaException { - PropertyTypeNode node = getConditionSubClassIdNode(); - node.setValue(new Variant(value)); - } - - @Override - public NodeId[] readConditionSubClassId() throws UaException { - try { - return readConditionSubClassIdAsync().get(); - } catch (ExecutionException | InterruptedException e) { - throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); - } - } - - @Override - public void writeConditionSubClassId(NodeId[] value) throws UaException { - try { - writeConditionSubClassIdAsync(value).get(); - } catch (ExecutionException | InterruptedException e) { - throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); - } - } - - @Override - public CompletableFuture readConditionSubClassIdAsync() { - return getConditionSubClassIdNodeAsync() - .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) - .thenApply(v -> (NodeId[]) v.getValue().getValue()); - } - - @Override - public CompletableFuture writeConditionSubClassIdAsync(NodeId[] conditionSubClassId) { - DataValue value = DataValue.valueOnly(new Variant(conditionSubClassId)); - return getConditionSubClassIdNodeAsync() - .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); - } - - @Override - public PropertyTypeNode getConditionSubClassIdNode() throws UaException { - try { - return getConditionSubClassIdNodeAsync().get(); - } catch (ExecutionException | InterruptedException e) { - throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); - } - } - - @Override - public CompletableFuture getConditionSubClassIdNodeAsync() { - CompletableFuture future = getMemberNodeAsync( - "http://opcfoundation.org/UA/", - "ConditionSubClassId", - ExpandedNodeId.parse("ns=0;i=46"), - false - ); - return future.thenApply(node -> (PropertyTypeNode) node); - } - - @Override - public LocalizedText[] getConditionSubClassName() throws UaException { - PropertyTypeNode node = getConditionSubClassNameNode(); - return (LocalizedText[]) node.getValue().getValue().getValue(); - } - - @Override - public void setConditionSubClassName(LocalizedText[] value) throws UaException { - PropertyTypeNode node = getConditionSubClassNameNode(); - node.setValue(new Variant(value)); - } - - @Override - public LocalizedText[] readConditionSubClassName() throws UaException { - try { - return readConditionSubClassNameAsync().get(); - } catch (ExecutionException | InterruptedException e) { - throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); - } - } - - @Override - public void writeConditionSubClassName(LocalizedText[] value) throws UaException { - try { - writeConditionSubClassNameAsync(value).get(); - } catch (ExecutionException | InterruptedException e) { - throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); - } - } - - @Override - public CompletableFuture readConditionSubClassNameAsync() { - return getConditionSubClassNameNodeAsync() - .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) - .thenApply(v -> (LocalizedText[]) v.getValue().getValue()); - } - - @Override - public CompletableFuture writeConditionSubClassNameAsync( - LocalizedText[] conditionSubClassName) { - DataValue value = DataValue.valueOnly(new Variant(conditionSubClassName)); - return getConditionSubClassNameNodeAsync() - .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); - } - - @Override - public PropertyTypeNode getConditionSubClassNameNode() throws UaException { - try { - return getConditionSubClassNameNodeAsync().get(); - } catch (ExecutionException | InterruptedException e) { - throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); - } - } - - @Override - public CompletableFuture getConditionSubClassNameNodeAsync() { - CompletableFuture future = getMemberNodeAsync( - "http://opcfoundation.org/UA/", - "ConditionSubClassName", - ExpandedNodeId.parse("ns=0;i=46"), - false - ); - return future.thenApply(node -> (PropertyTypeNode) node); - } - @Override public String getConditionName() throws UaException { PropertyTypeNode node = getConditionNameNode(); @@ -494,6 +365,71 @@ public CompletableFuture getRetainNodeAsync() { return future.thenApply(node -> (PropertyTypeNode) node); } + @Override + public Boolean getSupportsFilteredRetain() throws UaException { + PropertyTypeNode node = getSupportsFilteredRetainNode(); + return (Boolean) node.getValue().getValue().getValue(); + } + + @Override + public void setSupportsFilteredRetain(Boolean value) throws UaException { + PropertyTypeNode node = getSupportsFilteredRetainNode(); + node.setValue(new Variant(value)); + } + + @Override + public Boolean readSupportsFilteredRetain() throws UaException { + try { + return readSupportsFilteredRetainAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeSupportsFilteredRetain(Boolean value) throws UaException { + try { + writeSupportsFilteredRetainAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readSupportsFilteredRetainAsync() { + return getSupportsFilteredRetainNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (Boolean) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeSupportsFilteredRetainAsync( + Boolean supportsFilteredRetain) { + DataValue value = DataValue.valueOnly(new Variant(supportsFilteredRetain)); + return getSupportsFilteredRetainNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getSupportsFilteredRetainNode() throws UaException { + try { + return getSupportsFilteredRetainNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getSupportsFilteredRetainNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "SupportsFilteredRetain", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + @Override public String getClientUserId() throws UaException { PropertyTypeNode node = getClientUserIdNode(); diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DatagramDataSetReaderTransportType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DatagramDataSetReaderTransportType.java index 8d6f1ffaf..9245aa083 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DatagramDataSetReaderTransportType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DatagramDataSetReaderTransportType.java @@ -22,7 +22,7 @@ /** * @see https://reference.opcfoundation.org/v105/Core/docs/Part14/9.3.1/#9.3.1.4 */ -public interface DatagramDataSetReaderTransportType extends WriterGroupTransportType { +public interface DatagramDataSetReaderTransportType extends DataSetReaderTransportType { QualifiedProperty QOS_CATEGORY = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "QosCategory", diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DatagramDataSetReaderTransportTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DatagramDataSetReaderTransportTypeNode.java index 835ad910c..618ea015b 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DatagramDataSetReaderTransportTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DatagramDataSetReaderTransportTypeNode.java @@ -34,7 +34,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.ReceiveQosDataType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; -public class DatagramDataSetReaderTransportTypeNode extends WriterGroupTransportTypeNode implements DatagramDataSetReaderTransportType { +public class DatagramDataSetReaderTransportTypeNode extends DataSetReaderTransportTypeNode implements DatagramDataSetReaderTransportType { public DatagramDataSetReaderTransportTypeNode(OpcUaClient client, NodeId nodeId, NodeClass nodeClass, QualifiedName browseName, LocalizedText displayName, LocalizedText description, UInteger writeMask, UInteger userWriteMask, diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DiscrepancyAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DiscrepancyAlarmType.java index 4c4fb6dfe..f96ae4de2 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DiscrepancyAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DiscrepancyAlarmType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.25 */ public interface DiscrepancyAlarmType extends AlarmConditionType { QualifiedProperty TARGET_VALUE_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DiscreteAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DiscreteAlarmType.java index 057eb28d0..bbb4a2717 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DiscreteAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/DiscreteAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.1 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.1 */ public interface DiscreteAlarmType extends AlarmConditionType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccApplicationCertificateType.java index cb781a6cf..b15826929 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.6 */ public interface EccApplicationCertificateType extends ApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccBrainpoolP256r1ApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccBrainpoolP256r1ApplicationCertificateType.java index 0ac567405..10ad65967 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccBrainpoolP256r1ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccBrainpoolP256r1ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.9 */ public interface EccBrainpoolP256r1ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccBrainpoolP384r1ApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccBrainpoolP384r1ApplicationCertificateType.java index 2aee13e27..e5e3f99dc 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccBrainpoolP384r1ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccBrainpoolP384r1ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.10 */ public interface EccBrainpoolP384r1ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccCurve25519ApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccCurve25519ApplicationCertificateType.java index 2968c9d15..c991c96e7 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccCurve25519ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccCurve25519ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.11 */ public interface EccCurve25519ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccCurve448ApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccCurve448ApplicationCertificateType.java index 93605ae7b..e96b665bc 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccCurve448ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccCurve448ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.12 */ public interface EccCurve448ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccNistP256ApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccNistP256ApplicationCertificateType.java index 7c36bd61f..53174a9c5 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccNistP256ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccNistP256ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.7 */ public interface EccNistP256ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccNistP384ApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccNistP384ApplicationCertificateType.java index 675bc43ce..2b26bbb16 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccNistP384ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/EccNistP384ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.8 */ public interface EccNistP384ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveDeviationAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveDeviationAlarmType.java index fbb60b609..7cf34021f 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveDeviationAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveDeviationAlarmType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.21/#5.8.21.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.22/#5.8.22.3 */ public interface ExclusiveDeviationAlarmType extends ExclusiveLimitAlarmType { QualifiedProperty SETPOINT_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLevelAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLevelAlarmType.java index ede076367..02b6c2ed1 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLevelAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLevelAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.20/#5.8.20.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.21/#5.8.21.3 */ public interface ExclusiveLevelAlarmType extends ExclusiveLimitAlarmType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLimitAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLimitAlarmType.java index fb9d33517..72bb97ae2 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLimitAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLimitAlarmType.java @@ -18,7 +18,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.18/#5.8.18.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.19/#5.8.19.3 */ public interface ExclusiveLimitAlarmType extends LimitAlarmType { /** diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLimitStateMachineType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLimitStateMachineType.java index 06906ac81..7bf3869c6 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLimitStateMachineType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveLimitStateMachineType.java @@ -15,7 +15,7 @@ import org.eclipse.milo.opcua.stack.core.UaException; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.18/#5.8.18.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.19/#5.8.19.2 */ public interface ExclusiveLimitStateMachineType extends FiniteStateMachineType { /** diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveRateOfChangeAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveRateOfChangeAlarmType.java index 1c20ff81f..703b19b97 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveRateOfChangeAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ExclusiveRateOfChangeAlarmType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.EUInformation; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.22/#5.8.22.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.3 */ public interface ExclusiveRateOfChangeAlarmType extends ExclusiveLimitAlarmType { QualifiedProperty ENGINEERING_UNITS = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HistoricalDataConfigurationType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HistoricalDataConfigurationType.java index 64725e81f..80bed7eb2 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HistoricalDataConfigurationType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HistoricalDataConfigurationType.java @@ -21,7 +21,7 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.ExceptionDeviationFormat; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.2.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.2.2 */ public interface HistoricalDataConfigurationType extends BaseObjectType { QualifiedProperty STEPPED = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HistoryServerCapabilitiesType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HistoryServerCapabilitiesType.java index 2fe45be9f..2757f0552 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HistoryServerCapabilitiesType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HistoryServerCapabilitiesType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.4.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.4.2 */ public interface HistoryServerCapabilitiesType extends BaseObjectType { QualifiedProperty ACCESS_HISTORY_DATA_CAPABILITY = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HttpsCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HttpsCertificateType.java index bbef540f6..b2c02574d 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HttpsCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/HttpsCertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.3 + */ public interface HttpsCertificateType extends CertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/InstrumentDiagnosticAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/InstrumentDiagnosticAlarmType.java index 3da2e04bc..d1ecda01c 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/InstrumentDiagnosticAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/InstrumentDiagnosticAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.5 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.5 */ public interface InstrumentDiagnosticAlarmType extends OffNormalAlarmType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialAuditEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialAuditEventType.java index 7c183e8d0..a5235c970 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialAuditEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialAuditEventType.java @@ -18,6 +18,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.5.8 + */ public interface KeyCredentialAuditEventType extends AuditUpdateMethodEventType { QualifiedProperty RESOURCE_URI = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialConfigurationFolderType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialConfigurationFolderType.java index 32e420067..658e9fed1 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialConfigurationFolderType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialConfigurationFolderType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.6.1 + */ public interface KeyCredentialConfigurationFolderType extends FolderType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialConfigurationType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialConfigurationType.java index 8befdd200..1c1ab493a 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialConfigurationType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialConfigurationType.java @@ -19,7 +19,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.6.4 */ public interface KeyCredentialConfigurationType extends BaseObjectType { QualifiedProperty RESOURCE_URI = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialDeletedAuditEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialDeletedAuditEventType.java index 00c0fdcb1..ff31bac31 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialDeletedAuditEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialDeletedAuditEventType.java @@ -18,6 +18,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.6.9 + */ public interface KeyCredentialDeletedAuditEventType extends KeyCredentialAuditEventType { QualifiedProperty RESOURCE_URI = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialUpdatedAuditEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialUpdatedAuditEventType.java index ac2e874a1..8ed62a3f1 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialUpdatedAuditEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/KeyCredentialUpdatedAuditEventType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.6.8 + */ public interface KeyCredentialUpdatedAuditEventType extends KeyCredentialAuditEventType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/LimitAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/LimitAlarmType.java index 7d85aabd0..56fe773f6 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/LimitAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/LimitAlarmType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.17 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.18 */ public interface LimitAlarmType extends AlarmConditionType { QualifiedProperty HIGH_HIGH_LIMIT = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveDeviationAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveDeviationAlarmType.java index 720a33854..38b498ad6 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveDeviationAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveDeviationAlarmType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.21/#5.8.21.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.22/#5.8.22.2 */ public interface NonExclusiveDeviationAlarmType extends NonExclusiveLimitAlarmType { QualifiedProperty SETPOINT_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveLevelAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveLevelAlarmType.java index b59c3779b..8b4455eeb 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveLevelAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveLevelAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.20/#5.8.20.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.21/#5.8.21.2 */ public interface NonExclusiveLevelAlarmType extends NonExclusiveLimitAlarmType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveLimitAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveLimitAlarmType.java index 3438c31cf..62f508910 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveLimitAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveLimitAlarmType.java @@ -18,7 +18,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.19 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.20 */ public interface NonExclusiveLimitAlarmType extends LimitAlarmType { /** diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveRateOfChangeAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveRateOfChangeAlarmType.java index a8aa77e9d..49321bb3f 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveRateOfChangeAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/NonExclusiveRateOfChangeAlarmType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.EUInformation; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.22/#5.8.22.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.2 */ public interface NonExclusiveRateOfChangeAlarmType extends NonExclusiveLimitAlarmType { QualifiedProperty ENGINEERING_UNITS = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/OffNormalAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/OffNormalAlarmType.java index 6b1b48d50..ec36504f7 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/OffNormalAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/OffNormalAlarmType.java @@ -20,7 +20,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.2 */ public interface OffNormalAlarmType extends DiscreteAlarmType { QualifiedProperty NORMAL_STATE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ProvisionableDeviceType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ProvisionableDeviceType.java new file mode 100644 index 000000000..10b87cf97 --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ProvisionableDeviceType.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.client.model.variables.PropertyType; +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part21/9.3.3 + */ +public interface ProvisionableDeviceType extends BaseObjectType { + QualifiedProperty IS_SINGLETON = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "IsSingleton", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + + /** + * Get the local value of the IsSingleton Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the IsSingleton Node. + * @throws UaException if an error occurs creating or getting the IsSingleton Node. + */ + Boolean getIsSingleton() throws UaException; + + /** + * Set the local value of the IsSingleton Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the IsSingleton Node. + * @throws UaException if an error occurs creating or getting the IsSingleton Node. + */ + void setIsSingleton(Boolean value) throws UaException; + + /** + * Read the value of the IsSingleton Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link Boolean} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + Boolean readIsSingleton() throws UaException; + + /** + * Write a new value for the IsSingleton Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link Boolean} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeIsSingleton(Boolean value) throws UaException; + + /** + * An asynchronous implementation of {@link #readIsSingleton}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readIsSingletonAsync(); + + /** + * An asynchronous implementation of {@link #writeIsSingleton}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeIsSingletonAsync(Boolean value); + + /** + * Get the IsSingleton {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the IsSingleton {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getIsSingletonNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getIsSingletonNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getIsSingletonNodeAsync(); +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ProvisionableDeviceTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ProvisionableDeviceTypeNode.java new file mode 100644 index 000000000..e0d7befbb --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ProvisionableDeviceTypeNode.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; +import org.eclipse.milo.opcua.sdk.client.model.variables.PropertyTypeNode; +import org.eclipse.milo.opcua.sdk.client.nodes.UaNode; +import org.eclipse.milo.opcua.stack.core.AttributeId; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class ProvisionableDeviceTypeNode extends BaseObjectTypeNode implements ProvisionableDeviceType { + public ProvisionableDeviceTypeNode(OpcUaClient client, NodeId nodeId, NodeClass nodeClass, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } + + @Override + public Boolean getIsSingleton() throws UaException { + PropertyTypeNode node = getIsSingletonNode(); + return (Boolean) node.getValue().getValue().getValue(); + } + + @Override + public void setIsSingleton(Boolean value) throws UaException { + PropertyTypeNode node = getIsSingletonNode(); + node.setValue(new Variant(value)); + } + + @Override + public Boolean readIsSingleton() throws UaException { + try { + return readIsSingletonAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeIsSingleton(Boolean value) throws UaException { + try { + writeIsSingletonAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readIsSingletonAsync() { + return getIsSingletonNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (Boolean) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeIsSingletonAsync(Boolean isSingleton) { + DataValue value = DataValue.valueOnly(new Variant(isSingleton)); + return getIsSingletonNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getIsSingletonNode() throws UaException { + try { + return getIsSingletonNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getIsSingletonNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "IsSingleton", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PubSubCapabilitiesType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PubSubCapabilitiesType.java index b7ed65414..2cca9bf24 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PubSubCapabilitiesType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PubSubCapabilitiesType.java @@ -71,6 +71,46 @@ public interface PubSubCapabilitiesType extends BaseObjectType { UInteger.class ); + QualifiedProperty MAX_DATA_SET_WRITERS_PER_GROUP = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "MaxDataSetWritersPerGroup", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty MAX_NETWORK_MESSAGE_SIZE_DATAGRAM = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "MaxNetworkMessageSizeDatagram", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty MAX_NETWORK_MESSAGE_SIZE_BROKER = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "MaxNetworkMessageSizeBroker", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty SUPPORT_SECURITY_KEY_PULL = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "SupportSecurityKeyPull", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + + QualifiedProperty SUPPORT_SECURITY_KEY_PUSH = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "SupportSecurityKeyPush", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + /** * Get the local value of the MaxPubSubConnections Node. *

@@ -508,4 +548,369 @@ public interface PubSubCapabilitiesType extends BaseObjectType { * getting the Node. */ CompletableFuture getMaxFieldsPerDataSetNodeAsync(); + + /** + * Get the local value of the MaxDataSetWritersPerGroup Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the MaxDataSetWritersPerGroup Node. + * @throws UaException if an error occurs creating or getting the MaxDataSetWritersPerGroup Node. + */ + UInteger getMaxDataSetWritersPerGroup() throws UaException; + + /** + * Set the local value of the MaxDataSetWritersPerGroup Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the MaxDataSetWritersPerGroup Node. + * @throws UaException if an error occurs creating or getting the MaxDataSetWritersPerGroup Node. + */ + void setMaxDataSetWritersPerGroup(UInteger value) throws UaException; + + /** + * Read the value of the MaxDataSetWritersPerGroup Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link UInteger} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + UInteger readMaxDataSetWritersPerGroup() throws UaException; + + /** + * Write a new value for the MaxDataSetWritersPerGroup Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link UInteger} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeMaxDataSetWritersPerGroup(UInteger value) throws UaException; + + /** + * An asynchronous implementation of {@link #readMaxDataSetWritersPerGroup}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readMaxDataSetWritersPerGroupAsync(); + + /** + * An asynchronous implementation of {@link #writeMaxDataSetWritersPerGroup}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeMaxDataSetWritersPerGroupAsync(UInteger value); + + /** + * Get the MaxDataSetWritersPerGroup {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the MaxDataSetWritersPerGroup {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getMaxDataSetWritersPerGroupNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getMaxDataSetWritersPerGroupNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getMaxDataSetWritersPerGroupNodeAsync(); + + /** + * Get the local value of the MaxNetworkMessageSizeDatagram Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the MaxNetworkMessageSizeDatagram Node. + * @throws UaException if an error occurs creating or getting the MaxNetworkMessageSizeDatagram Node. + */ + UInteger getMaxNetworkMessageSizeDatagram() throws UaException; + + /** + * Set the local value of the MaxNetworkMessageSizeDatagram Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the MaxNetworkMessageSizeDatagram Node. + * @throws UaException if an error occurs creating or getting the MaxNetworkMessageSizeDatagram Node. + */ + void setMaxNetworkMessageSizeDatagram(UInteger value) throws UaException; + + /** + * Read the value of the MaxNetworkMessageSizeDatagram Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link UInteger} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + UInteger readMaxNetworkMessageSizeDatagram() throws UaException; + + /** + * Write a new value for the MaxNetworkMessageSizeDatagram Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link UInteger} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeMaxNetworkMessageSizeDatagram(UInteger value) throws UaException; + + /** + * An asynchronous implementation of {@link #readMaxNetworkMessageSizeDatagram}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readMaxNetworkMessageSizeDatagramAsync(); + + /** + * An asynchronous implementation of {@link #writeMaxNetworkMessageSizeDatagram}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeMaxNetworkMessageSizeDatagramAsync(UInteger value); + + /** + * Get the MaxNetworkMessageSizeDatagram {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the MaxNetworkMessageSizeDatagram {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getMaxNetworkMessageSizeDatagramNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getMaxNetworkMessageSizeDatagramNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getMaxNetworkMessageSizeDatagramNodeAsync(); + + /** + * Get the local value of the MaxNetworkMessageSizeBroker Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the MaxNetworkMessageSizeBroker Node. + * @throws UaException if an error occurs creating or getting the MaxNetworkMessageSizeBroker Node. + */ + UInteger getMaxNetworkMessageSizeBroker() throws UaException; + + /** + * Set the local value of the MaxNetworkMessageSizeBroker Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the MaxNetworkMessageSizeBroker Node. + * @throws UaException if an error occurs creating or getting the MaxNetworkMessageSizeBroker Node. + */ + void setMaxNetworkMessageSizeBroker(UInteger value) throws UaException; + + /** + * Read the value of the MaxNetworkMessageSizeBroker Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link UInteger} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + UInteger readMaxNetworkMessageSizeBroker() throws UaException; + + /** + * Write a new value for the MaxNetworkMessageSizeBroker Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link UInteger} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeMaxNetworkMessageSizeBroker(UInteger value) throws UaException; + + /** + * An asynchronous implementation of {@link #readMaxNetworkMessageSizeBroker}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readMaxNetworkMessageSizeBrokerAsync(); + + /** + * An asynchronous implementation of {@link #writeMaxNetworkMessageSizeBroker}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeMaxNetworkMessageSizeBrokerAsync(UInteger value); + + /** + * Get the MaxNetworkMessageSizeBroker {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the MaxNetworkMessageSizeBroker {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getMaxNetworkMessageSizeBrokerNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getMaxNetworkMessageSizeBrokerNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getMaxNetworkMessageSizeBrokerNodeAsync(); + + /** + * Get the local value of the SupportSecurityKeyPull Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the SupportSecurityKeyPull Node. + * @throws UaException if an error occurs creating or getting the SupportSecurityKeyPull Node. + */ + Boolean getSupportSecurityKeyPull() throws UaException; + + /** + * Set the local value of the SupportSecurityKeyPull Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the SupportSecurityKeyPull Node. + * @throws UaException if an error occurs creating or getting the SupportSecurityKeyPull Node. + */ + void setSupportSecurityKeyPull(Boolean value) throws UaException; + + /** + * Read the value of the SupportSecurityKeyPull Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link Boolean} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + Boolean readSupportSecurityKeyPull() throws UaException; + + /** + * Write a new value for the SupportSecurityKeyPull Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link Boolean} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeSupportSecurityKeyPull(Boolean value) throws UaException; + + /** + * An asynchronous implementation of {@link #readSupportSecurityKeyPull}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readSupportSecurityKeyPullAsync(); + + /** + * An asynchronous implementation of {@link #writeSupportSecurityKeyPull}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeSupportSecurityKeyPullAsync(Boolean value); + + /** + * Get the SupportSecurityKeyPull {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the SupportSecurityKeyPull {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getSupportSecurityKeyPullNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getSupportSecurityKeyPullNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getSupportSecurityKeyPullNodeAsync(); + + /** + * Get the local value of the SupportSecurityKeyPush Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the SupportSecurityKeyPush Node. + * @throws UaException if an error occurs creating or getting the SupportSecurityKeyPush Node. + */ + Boolean getSupportSecurityKeyPush() throws UaException; + + /** + * Set the local value of the SupportSecurityKeyPush Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the SupportSecurityKeyPush Node. + * @throws UaException if an error occurs creating or getting the SupportSecurityKeyPush Node. + */ + void setSupportSecurityKeyPush(Boolean value) throws UaException; + + /** + * Read the value of the SupportSecurityKeyPush Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link Boolean} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + Boolean readSupportSecurityKeyPush() throws UaException; + + /** + * Write a new value for the SupportSecurityKeyPush Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link Boolean} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeSupportSecurityKeyPush(Boolean value) throws UaException; + + /** + * An asynchronous implementation of {@link #readSupportSecurityKeyPush}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readSupportSecurityKeyPushAsync(); + + /** + * An asynchronous implementation of {@link #writeSupportSecurityKeyPush}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeSupportSecurityKeyPushAsync(Boolean value); + + /** + * Get the SupportSecurityKeyPush {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the SupportSecurityKeyPush {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getSupportSecurityKeyPushNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getSupportSecurityKeyPushNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getSupportSecurityKeyPushNodeAsync(); } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PubSubCapabilitiesTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PubSubCapabilitiesTypeNode.java index b4ed51e5e..fa05669b2 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PubSubCapabilitiesTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PubSubCapabilitiesTypeNode.java @@ -425,4 +425,329 @@ public CompletableFuture getMaxFieldsPerDataSetNodeA ); return future.thenApply(node -> (PropertyTypeNode) node); } + + @Override + public UInteger getMaxDataSetWritersPerGroup() throws UaException { + PropertyTypeNode node = getMaxDataSetWritersPerGroupNode(); + return (UInteger) node.getValue().getValue().getValue(); + } + + @Override + public void setMaxDataSetWritersPerGroup(UInteger value) throws UaException { + PropertyTypeNode node = getMaxDataSetWritersPerGroupNode(); + node.setValue(new Variant(value)); + } + + @Override + public UInteger readMaxDataSetWritersPerGroup() throws UaException { + try { + return readMaxDataSetWritersPerGroupAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeMaxDataSetWritersPerGroup(UInteger value) throws UaException { + try { + writeMaxDataSetWritersPerGroupAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readMaxDataSetWritersPerGroupAsync() { + return getMaxDataSetWritersPerGroupNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (UInteger) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeMaxDataSetWritersPerGroupAsync( + UInteger maxDataSetWritersPerGroup) { + DataValue value = DataValue.valueOnly(new Variant(maxDataSetWritersPerGroup)); + return getMaxDataSetWritersPerGroupNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getMaxDataSetWritersPerGroupNode() throws UaException { + try { + return getMaxDataSetWritersPerGroupNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getMaxDataSetWritersPerGroupNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "MaxDataSetWritersPerGroup", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public UInteger getMaxNetworkMessageSizeDatagram() throws UaException { + PropertyTypeNode node = getMaxNetworkMessageSizeDatagramNode(); + return (UInteger) node.getValue().getValue().getValue(); + } + + @Override + public void setMaxNetworkMessageSizeDatagram(UInteger value) throws UaException { + PropertyTypeNode node = getMaxNetworkMessageSizeDatagramNode(); + node.setValue(new Variant(value)); + } + + @Override + public UInteger readMaxNetworkMessageSizeDatagram() throws UaException { + try { + return readMaxNetworkMessageSizeDatagramAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeMaxNetworkMessageSizeDatagram(UInteger value) throws UaException { + try { + writeMaxNetworkMessageSizeDatagramAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readMaxNetworkMessageSizeDatagramAsync() { + return getMaxNetworkMessageSizeDatagramNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (UInteger) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeMaxNetworkMessageSizeDatagramAsync( + UInteger maxNetworkMessageSizeDatagram) { + DataValue value = DataValue.valueOnly(new Variant(maxNetworkMessageSizeDatagram)); + return getMaxNetworkMessageSizeDatagramNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getMaxNetworkMessageSizeDatagramNode() throws UaException { + try { + return getMaxNetworkMessageSizeDatagramNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getMaxNetworkMessageSizeDatagramNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "MaxNetworkMessageSizeDatagram", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public UInteger getMaxNetworkMessageSizeBroker() throws UaException { + PropertyTypeNode node = getMaxNetworkMessageSizeBrokerNode(); + return (UInteger) node.getValue().getValue().getValue(); + } + + @Override + public void setMaxNetworkMessageSizeBroker(UInteger value) throws UaException { + PropertyTypeNode node = getMaxNetworkMessageSizeBrokerNode(); + node.setValue(new Variant(value)); + } + + @Override + public UInteger readMaxNetworkMessageSizeBroker() throws UaException { + try { + return readMaxNetworkMessageSizeBrokerAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeMaxNetworkMessageSizeBroker(UInteger value) throws UaException { + try { + writeMaxNetworkMessageSizeBrokerAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readMaxNetworkMessageSizeBrokerAsync() { + return getMaxNetworkMessageSizeBrokerNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (UInteger) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeMaxNetworkMessageSizeBrokerAsync( + UInteger maxNetworkMessageSizeBroker) { + DataValue value = DataValue.valueOnly(new Variant(maxNetworkMessageSizeBroker)); + return getMaxNetworkMessageSizeBrokerNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getMaxNetworkMessageSizeBrokerNode() throws UaException { + try { + return getMaxNetworkMessageSizeBrokerNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getMaxNetworkMessageSizeBrokerNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "MaxNetworkMessageSizeBroker", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public Boolean getSupportSecurityKeyPull() throws UaException { + PropertyTypeNode node = getSupportSecurityKeyPullNode(); + return (Boolean) node.getValue().getValue().getValue(); + } + + @Override + public void setSupportSecurityKeyPull(Boolean value) throws UaException { + PropertyTypeNode node = getSupportSecurityKeyPullNode(); + node.setValue(new Variant(value)); + } + + @Override + public Boolean readSupportSecurityKeyPull() throws UaException { + try { + return readSupportSecurityKeyPullAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeSupportSecurityKeyPull(Boolean value) throws UaException { + try { + writeSupportSecurityKeyPullAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readSupportSecurityKeyPullAsync() { + return getSupportSecurityKeyPullNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (Boolean) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeSupportSecurityKeyPullAsync( + Boolean supportSecurityKeyPull) { + DataValue value = DataValue.valueOnly(new Variant(supportSecurityKeyPull)); + return getSupportSecurityKeyPullNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getSupportSecurityKeyPullNode() throws UaException { + try { + return getSupportSecurityKeyPullNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getSupportSecurityKeyPullNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "SupportSecurityKeyPull", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public Boolean getSupportSecurityKeyPush() throws UaException { + PropertyTypeNode node = getSupportSecurityKeyPushNode(); + return (Boolean) node.getValue().getValue().getValue(); + } + + @Override + public void setSupportSecurityKeyPush(Boolean value) throws UaException { + PropertyTypeNode node = getSupportSecurityKeyPushNode(); + node.setValue(new Variant(value)); + } + + @Override + public Boolean readSupportSecurityKeyPush() throws UaException { + try { + return readSupportSecurityKeyPushAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeSupportSecurityKeyPush(Boolean value) throws UaException { + try { + writeSupportSecurityKeyPushAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readSupportSecurityKeyPushAsync() { + return getSupportSecurityKeyPushNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (Boolean) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeSupportSecurityKeyPushAsync( + Boolean supportSecurityKeyPush) { + DataValue value = DataValue.valueOnly(new Variant(supportSecurityKeyPush)); + return getSupportSecurityKeyPushNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getSupportSecurityKeyPushNode() throws UaException { + try { + return getSupportSecurityKeyPushNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getSupportSecurityKeyPushNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "SupportSecurityKeyPush", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PublishSubscribeType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PublishSubscribeType.java index eddae5d0b..373e40cd3 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PublishSubscribeType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PublishSubscribeType.java @@ -19,6 +19,8 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.ULong; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.KeyValuePair; /** * @see https://reference.opcfoundation.org/v105/Core/docs/Part14/9.1.3/#9.1.3.2 @@ -48,6 +50,22 @@ public interface PublishSubscribeType extends PubSubKeyServiceType { UInteger.class ); + QualifiedProperty DEFAULT_SECURITY_KEY_SERVICES = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "DefaultSecurityKeyServices", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=312"), + 1, + EndpointDescription[].class + ); + + QualifiedProperty CONFIGURATION_PROPERTIES = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConfigurationProperties", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=14533"), + 1, + KeyValuePair[].class + ); + /** * Get the local value of the SupportedTransportProfiles Node. *

@@ -267,6 +285,152 @@ public interface PublishSubscribeType extends PubSubKeyServiceType { */ CompletableFuture getConfigurationVersionNodeAsync(); + /** + * Get the local value of the DefaultSecurityKeyServices Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the DefaultSecurityKeyServices Node. + * @throws UaException if an error occurs creating or getting the DefaultSecurityKeyServices Node. + */ + EndpointDescription[] getDefaultSecurityKeyServices() throws UaException; + + /** + * Set the local value of the DefaultSecurityKeyServices Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the DefaultSecurityKeyServices Node. + * @throws UaException if an error occurs creating or getting the DefaultSecurityKeyServices Node. + */ + void setDefaultSecurityKeyServices(EndpointDescription[] value) throws UaException; + + /** + * Read the value of the DefaultSecurityKeyServices Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link EndpointDescription[]} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + EndpointDescription[] readDefaultSecurityKeyServices() throws UaException; + + /** + * Write a new value for the DefaultSecurityKeyServices Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link EndpointDescription[]} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeDefaultSecurityKeyServices(EndpointDescription[] value) throws UaException; + + /** + * An asynchronous implementation of {@link #readDefaultSecurityKeyServices}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readDefaultSecurityKeyServicesAsync(); + + /** + * An asynchronous implementation of {@link #writeDefaultSecurityKeyServices}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeDefaultSecurityKeyServicesAsync(EndpointDescription[] value); + + /** + * Get the DefaultSecurityKeyServices {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the DefaultSecurityKeyServices {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getDefaultSecurityKeyServicesNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getDefaultSecurityKeyServicesNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getDefaultSecurityKeyServicesNodeAsync(); + + /** + * Get the local value of the ConfigurationProperties Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ConfigurationProperties Node. + * @throws UaException if an error occurs creating or getting the ConfigurationProperties Node. + */ + KeyValuePair[] getConfigurationProperties() throws UaException; + + /** + * Set the local value of the ConfigurationProperties Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ConfigurationProperties Node. + * @throws UaException if an error occurs creating or getting the ConfigurationProperties Node. + */ + void setConfigurationProperties(KeyValuePair[] value) throws UaException; + + /** + * Read the value of the ConfigurationProperties Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link KeyValuePair[]} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + KeyValuePair[] readConfigurationProperties() throws UaException; + + /** + * Write a new value for the ConfigurationProperties Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link KeyValuePair[]} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeConfigurationProperties(KeyValuePair[] value) throws UaException; + + /** + * An asynchronous implementation of {@link #readConfigurationProperties}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readConfigurationPropertiesAsync(); + + /** + * An asynchronous implementation of {@link #writeConfigurationProperties}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeConfigurationPropertiesAsync(KeyValuePair[] value); + + /** + * Get the ConfigurationProperties {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ConfigurationProperties {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getConfigurationPropertiesNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getConfigurationPropertiesNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getConfigurationPropertiesNodeAsync(); + /** * Get the PublishedDataSets {@link DataSetFolderType} Node, or {@code null} if it does not exist. *

diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PublishSubscribeTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PublishSubscribeTypeNode.java index 258bffdc0..ce63affda 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PublishSubscribeTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/PublishSubscribeTypeNode.java @@ -21,6 +21,7 @@ import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; @@ -31,6 +32,8 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.ULong; import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.KeyValuePair; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; public class PublishSubscribeTypeNode extends PubSubKeyServiceTypeNode implements PublishSubscribeType { @@ -237,6 +240,140 @@ public CompletableFuture getConfigurationVersionNode return future.thenApply(node -> (PropertyTypeNode) node); } + @Override + public EndpointDescription[] getDefaultSecurityKeyServices() throws UaException { + PropertyTypeNode node = getDefaultSecurityKeyServicesNode(); + return cast(node.getValue().getValue().getValue(), EndpointDescription[].class); + } + + @Override + public void setDefaultSecurityKeyServices(EndpointDescription[] value) throws UaException { + PropertyTypeNode node = getDefaultSecurityKeyServicesNode(); + ExtensionObject[] encoded = ExtensionObject.encodeArray(client.getStaticEncodingContext(), value); + node.setValue(new Variant(encoded)); + } + + @Override + public EndpointDescription[] readDefaultSecurityKeyServices() throws UaException { + try { + return readDefaultSecurityKeyServicesAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeDefaultSecurityKeyServices(EndpointDescription[] value) throws UaException { + try { + writeDefaultSecurityKeyServicesAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readDefaultSecurityKeyServicesAsync() { + return getDefaultSecurityKeyServicesNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> cast(v.getValue().getValue(), EndpointDescription[].class)); + } + + @Override + public CompletableFuture writeDefaultSecurityKeyServicesAsync( + EndpointDescription[] defaultSecurityKeyServices) { + ExtensionObject[] encoded = ExtensionObject.encodeArray(client.getStaticEncodingContext(), defaultSecurityKeyServices); + DataValue value = DataValue.valueOnly(new Variant(encoded)); + return getDefaultSecurityKeyServicesNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getDefaultSecurityKeyServicesNode() throws UaException { + try { + return getDefaultSecurityKeyServicesNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getDefaultSecurityKeyServicesNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "DefaultSecurityKeyServices", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public KeyValuePair[] getConfigurationProperties() throws UaException { + PropertyTypeNode node = getConfigurationPropertiesNode(); + return cast(node.getValue().getValue().getValue(), KeyValuePair[].class); + } + + @Override + public void setConfigurationProperties(KeyValuePair[] value) throws UaException { + PropertyTypeNode node = getConfigurationPropertiesNode(); + ExtensionObject[] encoded = ExtensionObject.encodeArray(client.getStaticEncodingContext(), value); + node.setValue(new Variant(encoded)); + } + + @Override + public KeyValuePair[] readConfigurationProperties() throws UaException { + try { + return readConfigurationPropertiesAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeConfigurationProperties(KeyValuePair[] value) throws UaException { + try { + writeConfigurationPropertiesAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readConfigurationPropertiesAsync() { + return getConfigurationPropertiesNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> cast(v.getValue().getValue(), KeyValuePair[].class)); + } + + @Override + public CompletableFuture writeConfigurationPropertiesAsync( + KeyValuePair[] configurationProperties) { + ExtensionObject[] encoded = ExtensionObject.encodeArray(client.getStaticEncodingContext(), configurationProperties); + DataValue value = DataValue.valueOnly(new Variant(encoded)); + return getConfigurationPropertiesNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getConfigurationPropertiesNode() throws UaException { + try { + return getConfigurationPropertiesNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getConfigurationPropertiesNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ConfigurationProperties", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + @Override public DataSetFolderTypeNode getPublishedDataSetsNode() throws UaException { try { diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/RsaMinApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/RsaMinApplicationCertificateType.java index 84b08b10c..9918ab4fd 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/RsaMinApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/RsaMinApplicationCertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.4 + */ public interface RsaMinApplicationCertificateType extends ApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/RsaSha256ApplicationCertificateType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/RsaSha256ApplicationCertificateType.java index 9a51ab616..060136a29 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/RsaSha256ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/RsaSha256ApplicationCertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.5 + */ public interface RsaSha256ApplicationCertificateType extends ApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerCapabilitiesType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerCapabilitiesType.java index 4654ed47b..85824b664 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerCapabilitiesType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerCapabilitiesType.java @@ -162,6 +162,14 @@ public interface ServerCapabilitiesType extends BaseObjectType { UInteger.class ); + QualifiedProperty MAX_MONITORED_ITEMS_QUEUE_SIZE = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "MaxMonitoredItemsQueueSize", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + QualifiedProperty CONFORMANCE_UNITS = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "ConformanceUnits", @@ -1411,6 +1419,79 @@ public interface ServerCapabilitiesType extends BaseObjectType { */ CompletableFuture getMaxWhereClauseParametersNodeAsync(); + /** + * Get the local value of the MaxMonitoredItemsQueueSize Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the MaxMonitoredItemsQueueSize Node. + * @throws UaException if an error occurs creating or getting the MaxMonitoredItemsQueueSize Node. + */ + UInteger getMaxMonitoredItemsQueueSize() throws UaException; + + /** + * Set the local value of the MaxMonitoredItemsQueueSize Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the MaxMonitoredItemsQueueSize Node. + * @throws UaException if an error occurs creating or getting the MaxMonitoredItemsQueueSize Node. + */ + void setMaxMonitoredItemsQueueSize(UInteger value) throws UaException; + + /** + * Read the value of the MaxMonitoredItemsQueueSize Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link UInteger} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + UInteger readMaxMonitoredItemsQueueSize() throws UaException; + + /** + * Write a new value for the MaxMonitoredItemsQueueSize Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link UInteger} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeMaxMonitoredItemsQueueSize(UInteger value) throws UaException; + + /** + * An asynchronous implementation of {@link #readMaxMonitoredItemsQueueSize}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readMaxMonitoredItemsQueueSizeAsync(); + + /** + * An asynchronous implementation of {@link #writeMaxMonitoredItemsQueueSize}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeMaxMonitoredItemsQueueSizeAsync(UInteger value); + + /** + * Get the MaxMonitoredItemsQueueSize {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the MaxMonitoredItemsQueueSize {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getMaxMonitoredItemsQueueSizeNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getMaxMonitoredItemsQueueSizeNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getMaxMonitoredItemsQueueSizeNodeAsync(); + /** * Get the local value of the ConformanceUnits Node. *

diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerCapabilitiesTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerCapabilitiesTypeNode.java index 15435c571..58907826e 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerCapabilitiesTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerCapabilitiesTypeNode.java @@ -1144,6 +1144,71 @@ public CompletableFuture getMaxWhereClauseParameters return future.thenApply(node -> (PropertyTypeNode) node); } + @Override + public UInteger getMaxMonitoredItemsQueueSize() throws UaException { + PropertyTypeNode node = getMaxMonitoredItemsQueueSizeNode(); + return (UInteger) node.getValue().getValue().getValue(); + } + + @Override + public void setMaxMonitoredItemsQueueSize(UInteger value) throws UaException { + PropertyTypeNode node = getMaxMonitoredItemsQueueSizeNode(); + node.setValue(new Variant(value)); + } + + @Override + public UInteger readMaxMonitoredItemsQueueSize() throws UaException { + try { + return readMaxMonitoredItemsQueueSizeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeMaxMonitoredItemsQueueSize(UInteger value) throws UaException { + try { + writeMaxMonitoredItemsQueueSizeAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readMaxMonitoredItemsQueueSizeAsync() { + return getMaxMonitoredItemsQueueSizeNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (UInteger) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeMaxMonitoredItemsQueueSizeAsync( + UInteger maxMonitoredItemsQueueSize) { + DataValue value = DataValue.valueOnly(new Variant(maxMonitoredItemsQueueSize)); + return getMaxMonitoredItemsQueueSizeNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getMaxMonitoredItemsQueueSizeNode() throws UaException { + try { + return getMaxMonitoredItemsQueueSizeNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getMaxMonitoredItemsQueueSizeNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "MaxMonitoredItemsQueueSize", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + @Override public QualifiedName[] getConformanceUnits() throws UaException { PropertyTypeNode node = getConformanceUnitsNode(); diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerConfigurationType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerConfigurationType.java index 9ad40a5ec..52459b8d6 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerConfigurationType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerConfigurationType.java @@ -18,8 +18,36 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.10.3 + */ public interface ServerConfigurationType extends BaseObjectType { + QualifiedProperty APPLICATION_URI = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ApplicationUri", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23751"), + -1, + String.class + ); + + QualifiedProperty PRODUCT_URI = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ProductUri", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23751"), + -1, + String.class + ); + + QualifiedProperty APPLICATION_TYPE = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ApplicationType", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=307"), + -1, + ApplicationType.class + ); + QualifiedProperty SERVER_CAPABILITIES = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "ServerCapabilities", @@ -52,6 +80,233 @@ public interface ServerConfigurationType extends BaseObjectType { Boolean.class ); + QualifiedProperty HAS_SECURE_ELEMENT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "HasSecureElement", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + + /** + * Get the local value of the ApplicationUri Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ApplicationUri Node. + * @throws UaException if an error occurs creating or getting the ApplicationUri Node. + */ + String getApplicationUri() throws UaException; + + /** + * Set the local value of the ApplicationUri Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ApplicationUri Node. + * @throws UaException if an error occurs creating or getting the ApplicationUri Node. + */ + void setApplicationUri(String value) throws UaException; + + /** + * Read the value of the ApplicationUri Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link String} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + String readApplicationUri() throws UaException; + + /** + * Write a new value for the ApplicationUri Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link String} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeApplicationUri(String value) throws UaException; + + /** + * An asynchronous implementation of {@link #readApplicationUri}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readApplicationUriAsync(); + + /** + * An asynchronous implementation of {@link #writeApplicationUri}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeApplicationUriAsync(String value); + + /** + * Get the ApplicationUri {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ApplicationUri {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getApplicationUriNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getApplicationUriNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getApplicationUriNodeAsync(); + + /** + * Get the local value of the ProductUri Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ProductUri Node. + * @throws UaException if an error occurs creating or getting the ProductUri Node. + */ + String getProductUri() throws UaException; + + /** + * Set the local value of the ProductUri Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ProductUri Node. + * @throws UaException if an error occurs creating or getting the ProductUri Node. + */ + void setProductUri(String value) throws UaException; + + /** + * Read the value of the ProductUri Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link String} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + String readProductUri() throws UaException; + + /** + * Write a new value for the ProductUri Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link String} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeProductUri(String value) throws UaException; + + /** + * An asynchronous implementation of {@link #readProductUri}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readProductUriAsync(); + + /** + * An asynchronous implementation of {@link #writeProductUri}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeProductUriAsync(String value); + + /** + * Get the ProductUri {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ProductUri {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getProductUriNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getProductUriNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getProductUriNodeAsync(); + + /** + * Get the local value of the ApplicationType Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ApplicationType Node. + * @throws UaException if an error occurs creating or getting the ApplicationType Node. + */ + ApplicationType getApplicationType() throws UaException; + + /** + * Set the local value of the ApplicationType Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ApplicationType Node. + * @throws UaException if an error occurs creating or getting the ApplicationType Node. + */ + void setApplicationType(ApplicationType value) throws UaException; + + /** + * Read the value of the ApplicationType Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link ApplicationType} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + ApplicationType readApplicationType() throws UaException; + + /** + * Write a new value for the ApplicationType Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link ApplicationType} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeApplicationType(ApplicationType value) throws UaException; + + /** + * An asynchronous implementation of {@link #readApplicationType}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readApplicationTypeAsync(); + + /** + * An asynchronous implementation of {@link #writeApplicationType}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeApplicationTypeAsync(ApplicationType value); + + /** + * Get the ApplicationType {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ApplicationType {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getApplicationTypeNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getApplicationTypeNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getApplicationTypeNodeAsync(); + /** * Get the local value of the ServerCapabilities Node. *

@@ -344,6 +599,79 @@ public interface ServerConfigurationType extends BaseObjectType { */ CompletableFuture getMulticastDnsEnabledNodeAsync(); + /** + * Get the local value of the HasSecureElement Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the HasSecureElement Node. + * @throws UaException if an error occurs creating or getting the HasSecureElement Node. + */ + Boolean getHasSecureElement() throws UaException; + + /** + * Set the local value of the HasSecureElement Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the HasSecureElement Node. + * @throws UaException if an error occurs creating or getting the HasSecureElement Node. + */ + void setHasSecureElement(Boolean value) throws UaException; + + /** + * Read the value of the HasSecureElement Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link Boolean} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + Boolean readHasSecureElement() throws UaException; + + /** + * Write a new value for the HasSecureElement Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link Boolean} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeHasSecureElement(Boolean value) throws UaException; + + /** + * An asynchronous implementation of {@link #readHasSecureElement}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readHasSecureElementAsync(); + + /** + * An asynchronous implementation of {@link #writeHasSecureElement}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeHasSecureElementAsync(Boolean value); + + /** + * Get the HasSecureElement {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the HasSecureElement {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getHasSecureElementNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getHasSecureElementNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getHasSecureElementNodeAsync(); + /** * Get the CertificateGroups {@link CertificateGroupFolderType} Node, or {@code null} if it does not exist. *

@@ -362,4 +690,23 @@ public interface ServerConfigurationType extends BaseObjectType { * getting the Node. */ CompletableFuture getCertificateGroupsNodeAsync(); + + /** + * Get the TransactionDiagnostics {@link TransactionDiagnosticsType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the TransactionDiagnostics {@link TransactionDiagnosticsType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + TransactionDiagnosticsType getTransactionDiagnosticsNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getTransactionDiagnosticsNode()}. + * + * @return a CompletableFuture that completes successfully with the + * TransactionDiagnosticsType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getTransactionDiagnosticsNodeAsync(); } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerConfigurationTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerConfigurationTypeNode.java index f769c36df..a65128c19 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerConfigurationTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ServerConfigurationTypeNode.java @@ -28,6 +28,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; @@ -41,6 +42,213 @@ public ServerConfigurationTypeNode(OpcUaClient client, NodeId nodeId, NodeClass super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); } + @Override + public String getApplicationUri() throws UaException { + PropertyTypeNode node = getApplicationUriNode(); + return (String) node.getValue().getValue().getValue(); + } + + @Override + public void setApplicationUri(String value) throws UaException { + PropertyTypeNode node = getApplicationUriNode(); + node.setValue(new Variant(value)); + } + + @Override + public String readApplicationUri() throws UaException { + try { + return readApplicationUriAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeApplicationUri(String value) throws UaException { + try { + writeApplicationUriAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readApplicationUriAsync() { + return getApplicationUriNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (String) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeApplicationUriAsync(String applicationUri) { + DataValue value = DataValue.valueOnly(new Variant(applicationUri)); + return getApplicationUriNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getApplicationUriNode() throws UaException { + try { + return getApplicationUriNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getApplicationUriNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ApplicationUri", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public String getProductUri() throws UaException { + PropertyTypeNode node = getProductUriNode(); + return (String) node.getValue().getValue().getValue(); + } + + @Override + public void setProductUri(String value) throws UaException { + PropertyTypeNode node = getProductUriNode(); + node.setValue(new Variant(value)); + } + + @Override + public String readProductUri() throws UaException { + try { + return readProductUriAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeProductUri(String value) throws UaException { + try { + writeProductUriAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readProductUriAsync() { + return getProductUriNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (String) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeProductUriAsync(String productUri) { + DataValue value = DataValue.valueOnly(new Variant(productUri)); + return getProductUriNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getProductUriNode() throws UaException { + try { + return getProductUriNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getProductUriNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ProductUri", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public ApplicationType getApplicationType() throws UaException { + PropertyTypeNode node = getApplicationTypeNode(); + Object value = node.getValue().getValue().getValue(); + + if (value instanceof Integer) { + return ApplicationType.from((Integer) value); + } else if (value instanceof ApplicationType) { + return (ApplicationType) value; + } else { + return null; + } + } + + @Override + public void setApplicationType(ApplicationType value) throws UaException { + PropertyTypeNode node = getApplicationTypeNode(); + node.setValue(new Variant(value)); + } + + @Override + public ApplicationType readApplicationType() throws UaException { + try { + return readApplicationTypeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeApplicationType(ApplicationType value) throws UaException { + try { + writeApplicationTypeAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readApplicationTypeAsync() { + return getApplicationTypeNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> { + Object value = v.getValue().getValue(); + if (value instanceof Integer) { + return ApplicationType.from((Integer) value); + } else { + return null; + } + }); + } + + @Override + public CompletableFuture writeApplicationTypeAsync(ApplicationType applicationType) { + DataValue value = DataValue.valueOnly(new Variant(applicationType)); + return getApplicationTypeNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getApplicationTypeNode() throws UaException { + try { + return getApplicationTypeNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getApplicationTypeNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ApplicationType", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + @Override public String[] getServerCapabilities() throws UaException { PropertyTypeNode node = getServerCapabilitiesNode(); @@ -298,6 +506,70 @@ public CompletableFuture getMulticastDnsEnabledNodeA return future.thenApply(node -> (PropertyTypeNode) node); } + @Override + public Boolean getHasSecureElement() throws UaException { + PropertyTypeNode node = getHasSecureElementNode(); + return (Boolean) node.getValue().getValue().getValue(); + } + + @Override + public void setHasSecureElement(Boolean value) throws UaException { + PropertyTypeNode node = getHasSecureElementNode(); + node.setValue(new Variant(value)); + } + + @Override + public Boolean readHasSecureElement() throws UaException { + try { + return readHasSecureElementAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeHasSecureElement(Boolean value) throws UaException { + try { + writeHasSecureElementAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readHasSecureElementAsync() { + return getHasSecureElementNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (Boolean) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeHasSecureElementAsync(Boolean hasSecureElement) { + DataValue value = DataValue.valueOnly(new Variant(hasSecureElement)); + return getHasSecureElementNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getHasSecureElementNode() throws UaException { + try { + return getHasSecureElementNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getHasSecureElementNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "HasSecureElement", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + @Override public CertificateGroupFolderTypeNode getCertificateGroupsNode() throws UaException { try { @@ -318,4 +590,25 @@ public CompletableFuture getCertificat ); return future.thenApply(node -> (CertificateGroupFolderTypeNode) node); } + + @Override + public TransactionDiagnosticsTypeNode getTransactionDiagnosticsNode() throws UaException { + try { + return getTransactionDiagnosticsNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getTransactionDiagnosticsNodeAsync( + ) { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "TransactionDiagnostics", + ExpandedNodeId.parse("ns=0;i=47"), + false + ); + return future.thenApply(node -> (TransactionDiagnosticsTypeNode) node); + } } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ShelvedStateMachineType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ShelvedStateMachineType.java index f520e9cf3..2f4a001f4 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ShelvedStateMachineType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/ShelvedStateMachineType.java @@ -19,7 +19,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.16/#5.8.16.1 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.17/#5.8.17.1 */ public interface ShelvedStateMachineType extends FiniteStateMachineType { QualifiedProperty UNSHELVE_TIME = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/SystemDiagnosticAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/SystemDiagnosticAlarmType.java index 321b4ed88..5138dce2d 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/SystemDiagnosticAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/SystemDiagnosticAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.6 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.6 */ public interface SystemDiagnosticAlarmType extends OffNormalAlarmType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/SystemOffNormalAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/SystemOffNormalAlarmType.java index 4eccff3dd..92357b399 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/SystemOffNormalAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/SystemOffNormalAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.3 */ public interface SystemOffNormalAlarmType extends OffNormalAlarmType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TransactionDiagnosticsType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TransactionDiagnosticsType.java new file mode 100644 index 000000000..b1d98b0a1 --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TransactionDiagnosticsType.java @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.client.model.variables.PropertyType; +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.structured.TransactionErrorType; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.10.11 + */ +public interface TransactionDiagnosticsType extends BaseObjectType { + QualifiedProperty START_TIME = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "StartTime", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=294"), + -1, + DateTime.class + ); + + QualifiedProperty END_TIME = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "EndTime", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=294"), + -1, + DateTime.class + ); + + QualifiedProperty RESULT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "Result", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=19"), + -1, + StatusCode.class + ); + + QualifiedProperty AFFECTED_TRUST_LISTS = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "AffectedTrustLists", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + 1, + NodeId[].class + ); + + QualifiedProperty AFFECTED_CERTIFICATE_GROUPS = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "AffectedCertificateGroups", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + 1, + NodeId[].class + ); + + QualifiedProperty ERRORS = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "Errors", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=32285"), + 1, + TransactionErrorType[].class + ); + + /** + * Get the local value of the StartTime Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the StartTime Node. + * @throws UaException if an error occurs creating or getting the StartTime Node. + */ + DateTime getStartTime() throws UaException; + + /** + * Set the local value of the StartTime Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the StartTime Node. + * @throws UaException if an error occurs creating or getting the StartTime Node. + */ + void setStartTime(DateTime value) throws UaException; + + /** + * Read the value of the StartTime Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link DateTime} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + DateTime readStartTime() throws UaException; + + /** + * Write a new value for the StartTime Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link DateTime} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeStartTime(DateTime value) throws UaException; + + /** + * An asynchronous implementation of {@link #readStartTime}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readStartTimeAsync(); + + /** + * An asynchronous implementation of {@link #writeStartTime}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeStartTimeAsync(DateTime value); + + /** + * Get the StartTime {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the StartTime {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getStartTimeNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getStartTimeNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getStartTimeNodeAsync(); + + /** + * Get the local value of the EndTime Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the EndTime Node. + * @throws UaException if an error occurs creating or getting the EndTime Node. + */ + DateTime getEndTime() throws UaException; + + /** + * Set the local value of the EndTime Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the EndTime Node. + * @throws UaException if an error occurs creating or getting the EndTime Node. + */ + void setEndTime(DateTime value) throws UaException; + + /** + * Read the value of the EndTime Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link DateTime} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + DateTime readEndTime() throws UaException; + + /** + * Write a new value for the EndTime Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link DateTime} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeEndTime(DateTime value) throws UaException; + + /** + * An asynchronous implementation of {@link #readEndTime}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readEndTimeAsync(); + + /** + * An asynchronous implementation of {@link #writeEndTime}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeEndTimeAsync(DateTime value); + + /** + * Get the EndTime {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the EndTime {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getEndTimeNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getEndTimeNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getEndTimeNodeAsync(); + + /** + * Get the local value of the Result Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the Result Node. + * @throws UaException if an error occurs creating or getting the Result Node. + */ + StatusCode getResult() throws UaException; + + /** + * Set the local value of the Result Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the Result Node. + * @throws UaException if an error occurs creating or getting the Result Node. + */ + void setResult(StatusCode value) throws UaException; + + /** + * Read the value of the Result Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link StatusCode} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + StatusCode readResult() throws UaException; + + /** + * Write a new value for the Result Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link StatusCode} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeResult(StatusCode value) throws UaException; + + /** + * An asynchronous implementation of {@link #readResult}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readResultAsync(); + + /** + * An asynchronous implementation of {@link #writeResult}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeResultAsync(StatusCode value); + + /** + * Get the Result {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the Result {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getResultNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getResultNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getResultNodeAsync(); + + /** + * Get the local value of the AffectedTrustLists Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the AffectedTrustLists Node. + * @throws UaException if an error occurs creating or getting the AffectedTrustLists Node. + */ + NodeId[] getAffectedTrustLists() throws UaException; + + /** + * Set the local value of the AffectedTrustLists Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the AffectedTrustLists Node. + * @throws UaException if an error occurs creating or getting the AffectedTrustLists Node. + */ + void setAffectedTrustLists(NodeId[] value) throws UaException; + + /** + * Read the value of the AffectedTrustLists Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link NodeId[]} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + NodeId[] readAffectedTrustLists() throws UaException; + + /** + * Write a new value for the AffectedTrustLists Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link NodeId[]} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeAffectedTrustLists(NodeId[] value) throws UaException; + + /** + * An asynchronous implementation of {@link #readAffectedTrustLists}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readAffectedTrustListsAsync(); + + /** + * An asynchronous implementation of {@link #writeAffectedTrustLists}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeAffectedTrustListsAsync(NodeId[] value); + + /** + * Get the AffectedTrustLists {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the AffectedTrustLists {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getAffectedTrustListsNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getAffectedTrustListsNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getAffectedTrustListsNodeAsync(); + + /** + * Get the local value of the AffectedCertificateGroups Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the AffectedCertificateGroups Node. + * @throws UaException if an error occurs creating or getting the AffectedCertificateGroups Node. + */ + NodeId[] getAffectedCertificateGroups() throws UaException; + + /** + * Set the local value of the AffectedCertificateGroups Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the AffectedCertificateGroups Node. + * @throws UaException if an error occurs creating or getting the AffectedCertificateGroups Node. + */ + void setAffectedCertificateGroups(NodeId[] value) throws UaException; + + /** + * Read the value of the AffectedCertificateGroups Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link NodeId[]} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + NodeId[] readAffectedCertificateGroups() throws UaException; + + /** + * Write a new value for the AffectedCertificateGroups Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link NodeId[]} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeAffectedCertificateGroups(NodeId[] value) throws UaException; + + /** + * An asynchronous implementation of {@link #readAffectedCertificateGroups}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readAffectedCertificateGroupsAsync(); + + /** + * An asynchronous implementation of {@link #writeAffectedCertificateGroups}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeAffectedCertificateGroupsAsync(NodeId[] value); + + /** + * Get the AffectedCertificateGroups {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the AffectedCertificateGroups {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getAffectedCertificateGroupsNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getAffectedCertificateGroupsNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getAffectedCertificateGroupsNodeAsync(); + + /** + * Get the local value of the Errors Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the Errors Node. + * @throws UaException if an error occurs creating or getting the Errors Node. + */ + TransactionErrorType[] getErrors() throws UaException; + + /** + * Set the local value of the Errors Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the Errors Node. + * @throws UaException if an error occurs creating or getting the Errors Node. + */ + void setErrors(TransactionErrorType[] value) throws UaException; + + /** + * Read the value of the Errors Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link TransactionErrorType[]} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + TransactionErrorType[] readErrors() throws UaException; + + /** + * Write a new value for the Errors Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link TransactionErrorType[]} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeErrors(TransactionErrorType[] value) throws UaException; + + /** + * An asynchronous implementation of {@link #readErrors}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readErrorsAsync(); + + /** + * An asynchronous implementation of {@link #writeErrors}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeErrorsAsync(TransactionErrorType[] value); + + /** + * Get the Errors {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the Errors {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getErrorsNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getErrorsNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getErrorsNodeAsync(); +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TransactionDiagnosticsTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TransactionDiagnosticsTypeNode.java new file mode 100644 index 000000000..348d1a370 --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TransactionDiagnosticsTypeNode.java @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; +import org.eclipse.milo.opcua.sdk.client.model.variables.PropertyTypeNode; +import org.eclipse.milo.opcua.sdk.client.nodes.UaNode; +import org.eclipse.milo.opcua.stack.core.AttributeId; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; +import org.eclipse.milo.opcua.stack.core.types.structured.TransactionErrorType; + +public class TransactionDiagnosticsTypeNode extends BaseObjectTypeNode implements TransactionDiagnosticsType { + public TransactionDiagnosticsTypeNode(OpcUaClient client, NodeId nodeId, NodeClass nodeClass, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } + + @Override + public DateTime getStartTime() throws UaException { + PropertyTypeNode node = getStartTimeNode(); + return (DateTime) node.getValue().getValue().getValue(); + } + + @Override + public void setStartTime(DateTime value) throws UaException { + PropertyTypeNode node = getStartTimeNode(); + node.setValue(new Variant(value)); + } + + @Override + public DateTime readStartTime() throws UaException { + try { + return readStartTimeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeStartTime(DateTime value) throws UaException { + try { + writeStartTimeAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readStartTimeAsync() { + return getStartTimeNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (DateTime) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeStartTimeAsync(DateTime startTime) { + DataValue value = DataValue.valueOnly(new Variant(startTime)); + return getStartTimeNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getStartTimeNode() throws UaException { + try { + return getStartTimeNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getStartTimeNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "StartTime", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public DateTime getEndTime() throws UaException { + PropertyTypeNode node = getEndTimeNode(); + return (DateTime) node.getValue().getValue().getValue(); + } + + @Override + public void setEndTime(DateTime value) throws UaException { + PropertyTypeNode node = getEndTimeNode(); + node.setValue(new Variant(value)); + } + + @Override + public DateTime readEndTime() throws UaException { + try { + return readEndTimeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeEndTime(DateTime value) throws UaException { + try { + writeEndTimeAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readEndTimeAsync() { + return getEndTimeNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (DateTime) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeEndTimeAsync(DateTime endTime) { + DataValue value = DataValue.valueOnly(new Variant(endTime)); + return getEndTimeNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getEndTimeNode() throws UaException { + try { + return getEndTimeNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getEndTimeNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "EndTime", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public StatusCode getResult() throws UaException { + PropertyTypeNode node = getResultNode(); + return (StatusCode) node.getValue().getValue().getValue(); + } + + @Override + public void setResult(StatusCode value) throws UaException { + PropertyTypeNode node = getResultNode(); + node.setValue(new Variant(value)); + } + + @Override + public StatusCode readResult() throws UaException { + try { + return readResultAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeResult(StatusCode value) throws UaException { + try { + writeResultAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readResultAsync() { + return getResultNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (StatusCode) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeResultAsync(StatusCode result) { + DataValue value = DataValue.valueOnly(new Variant(result)); + return getResultNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getResultNode() throws UaException { + try { + return getResultNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getResultNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "Result", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public NodeId[] getAffectedTrustLists() throws UaException { + PropertyTypeNode node = getAffectedTrustListsNode(); + return (NodeId[]) node.getValue().getValue().getValue(); + } + + @Override + public void setAffectedTrustLists(NodeId[] value) throws UaException { + PropertyTypeNode node = getAffectedTrustListsNode(); + node.setValue(new Variant(value)); + } + + @Override + public NodeId[] readAffectedTrustLists() throws UaException { + try { + return readAffectedTrustListsAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeAffectedTrustLists(NodeId[] value) throws UaException { + try { + writeAffectedTrustListsAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readAffectedTrustListsAsync() { + return getAffectedTrustListsNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (NodeId[]) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeAffectedTrustListsAsync(NodeId[] affectedTrustLists) { + DataValue value = DataValue.valueOnly(new Variant(affectedTrustLists)); + return getAffectedTrustListsNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getAffectedTrustListsNode() throws UaException { + try { + return getAffectedTrustListsNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getAffectedTrustListsNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "AffectedTrustLists", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public NodeId[] getAffectedCertificateGroups() throws UaException { + PropertyTypeNode node = getAffectedCertificateGroupsNode(); + return (NodeId[]) node.getValue().getValue().getValue(); + } + + @Override + public void setAffectedCertificateGroups(NodeId[] value) throws UaException { + PropertyTypeNode node = getAffectedCertificateGroupsNode(); + node.setValue(new Variant(value)); + } + + @Override + public NodeId[] readAffectedCertificateGroups() throws UaException { + try { + return readAffectedCertificateGroupsAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeAffectedCertificateGroups(NodeId[] value) throws UaException { + try { + writeAffectedCertificateGroupsAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readAffectedCertificateGroupsAsync() { + return getAffectedCertificateGroupsNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (NodeId[]) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeAffectedCertificateGroupsAsync( + NodeId[] affectedCertificateGroups) { + DataValue value = DataValue.valueOnly(new Variant(affectedCertificateGroups)); + return getAffectedCertificateGroupsNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getAffectedCertificateGroupsNode() throws UaException { + try { + return getAffectedCertificateGroupsNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getAffectedCertificateGroupsNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "AffectedCertificateGroups", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public TransactionErrorType[] getErrors() throws UaException { + PropertyTypeNode node = getErrorsNode(); + return cast(node.getValue().getValue().getValue(), TransactionErrorType[].class); + } + + @Override + public void setErrors(TransactionErrorType[] value) throws UaException { + PropertyTypeNode node = getErrorsNode(); + ExtensionObject[] encoded = ExtensionObject.encodeArray(client.getStaticEncodingContext(), value); + node.setValue(new Variant(encoded)); + } + + @Override + public TransactionErrorType[] readErrors() throws UaException { + try { + return readErrorsAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeErrors(TransactionErrorType[] value) throws UaException { + try { + writeErrorsAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readErrorsAsync() { + return getErrorsNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> cast(v.getValue().getValue(), TransactionErrorType[].class)); + } + + @Override + public CompletableFuture writeErrorsAsync(TransactionErrorType[] errors) { + ExtensionObject[] encoded = ExtensionObject.encodeArray(client.getStaticEncodingContext(), errors); + DataValue value = DataValue.valueOnly(new Variant(encoded)); + return getErrorsNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getErrorsNode() throws UaException { + try { + return getErrorsNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getErrorsNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "Errors", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TripAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TripAlarmType.java index d0a5042f3..06d076388 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TripAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TripAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.4 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.4 */ public interface TripAlarmType extends OffNormalAlarmType { } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListOutOfDateAlarmType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListOutOfDateAlarmType.java index d6f77a5a1..ae5c6a55b 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListOutOfDateAlarmType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListOutOfDateAlarmType.java @@ -20,6 +20,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.2/#7.8.2.9 + */ public interface TrustListOutOfDateAlarmType extends SystemOffNormalAlarmType { QualifiedProperty TRUST_LIST_ID = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListType.java index 31309a804..a55a5d24b 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListType.java @@ -18,7 +18,11 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.structured.TrustListValidationOptions; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.2/#7.8.2.1 + */ public interface TrustListType extends FileType { QualifiedProperty LAST_UPDATE_TIME = new QualifiedProperty<>( "http://opcfoundation.org/UA/", @@ -36,6 +40,22 @@ public interface TrustListType extends FileType { Double.class ); + QualifiedProperty ACTIVITY_TIMEOUT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ActivityTimeout", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=290"), + -1, + Double.class + ); + + QualifiedProperty DEFAULT_VALIDATION_OPTIONS = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "DefaultValidationOptions", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23564"), + -1, + TrustListValidationOptions.class + ); + /** * Get the local value of the LastUpdateTime Node. *

@@ -181,4 +201,151 @@ public interface TrustListType extends FileType { * getting the Node. */ CompletableFuture getUpdateFrequencyNodeAsync(); + + /** + * Get the local value of the ActivityTimeout Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ActivityTimeout Node. + * @throws UaException if an error occurs creating or getting the ActivityTimeout Node. + */ + Double getActivityTimeout() throws UaException; + + /** + * Set the local value of the ActivityTimeout Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ActivityTimeout Node. + * @throws UaException if an error occurs creating or getting the ActivityTimeout Node. + */ + void setActivityTimeout(Double value) throws UaException; + + /** + * Read the value of the ActivityTimeout Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link Double} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + Double readActivityTimeout() throws UaException; + + /** + * Write a new value for the ActivityTimeout Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link Double} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeActivityTimeout(Double value) throws UaException; + + /** + * An asynchronous implementation of {@link #readActivityTimeout}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readActivityTimeoutAsync(); + + /** + * An asynchronous implementation of {@link #writeActivityTimeout}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeActivityTimeoutAsync(Double value); + + /** + * Get the ActivityTimeout {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ActivityTimeout {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getActivityTimeoutNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getActivityTimeoutNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getActivityTimeoutNodeAsync(); + + /** + * Get the local value of the DefaultValidationOptions Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the DefaultValidationOptions Node. + * @throws UaException if an error occurs creating or getting the DefaultValidationOptions Node. + */ + TrustListValidationOptions getDefaultValidationOptions() throws UaException; + + /** + * Set the local value of the DefaultValidationOptions Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the DefaultValidationOptions Node. + * @throws UaException if an error occurs creating or getting the DefaultValidationOptions Node. + */ + void setDefaultValidationOptions(TrustListValidationOptions value) throws UaException; + + /** + * Read the value of the DefaultValidationOptions Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link TrustListValidationOptions} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + TrustListValidationOptions readDefaultValidationOptions() throws UaException; + + /** + * Write a new value for the DefaultValidationOptions Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link TrustListValidationOptions} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeDefaultValidationOptions(TrustListValidationOptions value) throws UaException; + + /** + * An asynchronous implementation of {@link #readDefaultValidationOptions}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readDefaultValidationOptionsAsync(); + + /** + * An asynchronous implementation of {@link #writeDefaultValidationOptions}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeDefaultValidationOptionsAsync( + TrustListValidationOptions value); + + /** + * Get the DefaultValidationOptions {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the DefaultValidationOptions {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getDefaultValidationOptionsNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getDefaultValidationOptionsNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getDefaultValidationOptionsNodeAsync(); } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListTypeNode.java index 89fd3d0f1..fb4cc3d61 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListTypeNode.java @@ -32,6 +32,7 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; +import org.eclipse.milo.opcua.stack.core.types.structured.TrustListValidationOptions; public class TrustListTypeNode extends FileTypeNode implements TrustListType { public TrustListTypeNode(OpcUaClient client, NodeId nodeId, NodeClass nodeClass, @@ -169,4 +170,134 @@ public CompletableFuture getUpdateFrequencyNodeAsync ); return future.thenApply(node -> (PropertyTypeNode) node); } + + @Override + public Double getActivityTimeout() throws UaException { + PropertyTypeNode node = getActivityTimeoutNode(); + return (Double) node.getValue().getValue().getValue(); + } + + @Override + public void setActivityTimeout(Double value) throws UaException { + PropertyTypeNode node = getActivityTimeoutNode(); + node.setValue(new Variant(value)); + } + + @Override + public Double readActivityTimeout() throws UaException { + try { + return readActivityTimeoutAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeActivityTimeout(Double value) throws UaException { + try { + writeActivityTimeoutAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readActivityTimeoutAsync() { + return getActivityTimeoutNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (Double) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeActivityTimeoutAsync(Double activityTimeout) { + DataValue value = DataValue.valueOnly(new Variant(activityTimeout)); + return getActivityTimeoutNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getActivityTimeoutNode() throws UaException { + try { + return getActivityTimeoutNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getActivityTimeoutNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ActivityTimeout", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public TrustListValidationOptions getDefaultValidationOptions() throws UaException { + PropertyTypeNode node = getDefaultValidationOptionsNode(); + return (TrustListValidationOptions) node.getValue().getValue().getValue(); + } + + @Override + public void setDefaultValidationOptions(TrustListValidationOptions value) throws UaException { + PropertyTypeNode node = getDefaultValidationOptionsNode(); + node.setValue(new Variant(value)); + } + + @Override + public TrustListValidationOptions readDefaultValidationOptions() throws UaException { + try { + return readDefaultValidationOptionsAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeDefaultValidationOptions(TrustListValidationOptions value) throws UaException { + try { + writeDefaultValidationOptionsAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readDefaultValidationOptionsAsync( + ) { + return getDefaultValidationOptionsNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (TrustListValidationOptions) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeDefaultValidationOptionsAsync( + TrustListValidationOptions defaultValidationOptions) { + DataValue value = DataValue.valueOnly(new Variant(defaultValidationOptions)); + return getDefaultValidationOptionsNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getDefaultValidationOptionsNode() throws UaException { + try { + return getDefaultValidationOptionsNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getDefaultValidationOptionsNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "DefaultValidationOptions", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdateRequestedAuditEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdateRequestedAuditEventType.java new file mode 100644 index 000000000..0dbdebef6 --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdateRequestedAuditEventType.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.2/#7.8.2.10 + */ +public interface TrustListUpdateRequestedAuditEventType extends AuditUpdateMethodEventType { +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdateRequestedAuditEventTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdateRequestedAuditEventTypeNode.java new file mode 100644 index 000000000..1580588c8 --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdateRequestedAuditEventTypeNode.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.objects; + +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class TrustListUpdateRequestedAuditEventTypeNode extends AuditUpdateMethodEventTypeNode implements TrustListUpdateRequestedAuditEventType { + public TrustListUpdateRequestedAuditEventTypeNode(OpcUaClient client, NodeId nodeId, + NodeClass nodeClass, QualifiedName browseName, LocalizedText displayName, + LocalizedText description, UInteger writeMask, UInteger userWriteMask, + RolePermissionType[] rolePermissions, RolePermissionType[] userRolePermissions, + AccessRestrictionType accessRestrictions, UByte eventNotifier) { + super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdatedAuditEventType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdatedAuditEventType.java index 935029bd6..c0a06c9a2 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdatedAuditEventType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdatedAuditEventType.java @@ -10,5 +10,97 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; -public interface TrustListUpdatedAuditEventType extends AuditUpdateMethodEventType { +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.client.model.variables.PropertyType; +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.2/#7.8.2.11 + */ +public interface TrustListUpdatedAuditEventType extends AuditEventType { + QualifiedProperty TRUST_LIST_ID = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "TrustListId", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + -1, + NodeId.class + ); + + /** + * Get the local value of the TrustListId Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the TrustListId Node. + * @throws UaException if an error occurs creating or getting the TrustListId Node. + */ + NodeId getTrustListId() throws UaException; + + /** + * Set the local value of the TrustListId Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the TrustListId Node. + * @throws UaException if an error occurs creating or getting the TrustListId Node. + */ + void setTrustListId(NodeId value) throws UaException; + + /** + * Read the value of the TrustListId Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link NodeId} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + NodeId readTrustListId() throws UaException; + + /** + * Write a new value for the TrustListId Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link NodeId} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeTrustListId(NodeId value) throws UaException; + + /** + * An asynchronous implementation of {@link #readTrustListId}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readTrustListIdAsync(); + + /** + * An asynchronous implementation of {@link #writeTrustListId}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeTrustListIdAsync(NodeId value); + + /** + * Get the TrustListId {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the TrustListId {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getTrustListIdNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getTrustListIdNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getTrustListIdNodeAsync(); } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdatedAuditEventTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdatedAuditEventTypeNode.java index 840a6319e..a64284150 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdatedAuditEventTypeNode.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/objects/TrustListUpdatedAuditEventTypeNode.java @@ -10,17 +10,29 @@ package org.eclipse.milo.opcua.sdk.client.model.objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + import org.eclipse.milo.opcua.sdk.client.OpcUaClient; +import org.eclipse.milo.opcua.sdk.client.model.variables.PropertyTypeNode; +import org.eclipse.milo.opcua.sdk.client.nodes.UaNode; +import org.eclipse.milo.opcua.stack.core.AttributeId; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; -public class TrustListUpdatedAuditEventTypeNode extends AuditUpdateMethodEventTypeNode implements TrustListUpdatedAuditEventType { +public class TrustListUpdatedAuditEventTypeNode extends AuditEventTypeNode implements TrustListUpdatedAuditEventType { public TrustListUpdatedAuditEventTypeNode(OpcUaClient client, NodeId nodeId, NodeClass nodeClass, QualifiedName browseName, LocalizedText displayName, LocalizedText description, UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, @@ -28,4 +40,68 @@ public TrustListUpdatedAuditEventTypeNode(OpcUaClient client, NodeId nodeId, Nod UByte eventNotifier) { super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); } + + @Override + public NodeId getTrustListId() throws UaException { + PropertyTypeNode node = getTrustListIdNode(); + return (NodeId) node.getValue().getValue().getValue(); + } + + @Override + public void setTrustListId(NodeId value) throws UaException { + PropertyTypeNode node = getTrustListIdNode(); + node.setValue(new Variant(value)); + } + + @Override + public NodeId readTrustListId() throws UaException { + try { + return readTrustListIdAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeTrustListId(NodeId value) throws UaException { + try { + writeTrustListIdAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readTrustListIdAsync() { + return getTrustListIdNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (NodeId) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeTrustListIdAsync(NodeId trustListId) { + DataValue value = DataValue.valueOnly(new Variant(trustListId)); + return getTrustListIdNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getTrustListIdNode() throws UaException { + try { + return getTrustListIdNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getTrustListIdNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "TrustListId", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmRateVariableType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmRateVariableType.java index 70feabbec..a82e6fbc2 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmRateVariableType.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmRateVariableType.java @@ -19,7 +19,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/8.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/9.3 */ public interface AlarmRateVariableType extends BaseDataVariableType { QualifiedProperty RATE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmStateVariableType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmStateVariableType.java new file mode 100644 index 000000000..677b44b22 --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmStateVariableType.java @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.variables; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; +import org.eclipse.milo.opcua.stack.core.types.structured.ContentFilter; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/8.2 + */ +public interface AlarmStateVariableType extends BaseDataVariableType { + QualifiedProperty HIGHEST_ACTIVE_SEVERITY = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "HighestActiveSeverity", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=5"), + -1, + UShort.class + ); + + QualifiedProperty HIGHEST_UNACK_SEVERITY = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "HighestUnackSeverity", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=5"), + -1, + UShort.class + ); + + QualifiedProperty ACTIVE_COUNT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ActiveCount", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty UNACKNOWLEDGED_COUNT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "UnacknowledgedCount", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty UNCONFIRMED_COUNT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "UnconfirmedCount", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty FILTER = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "Filter", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=586"), + -1, + ContentFilter.class + ); + + /** + * Get the local value of the HighestActiveSeverity Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the HighestActiveSeverity Node. + * @throws UaException if an error occurs creating or getting the HighestActiveSeverity Node. + */ + UShort getHighestActiveSeverity() throws UaException; + + /** + * Set the local value of the HighestActiveSeverity Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the HighestActiveSeverity Node. + * @throws UaException if an error occurs creating or getting the HighestActiveSeverity Node. + */ + void setHighestActiveSeverity(UShort value) throws UaException; + + /** + * Read the value of the HighestActiveSeverity Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link UShort} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + UShort readHighestActiveSeverity() throws UaException; + + /** + * Write a new value for the HighestActiveSeverity Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link UShort} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeHighestActiveSeverity(UShort value) throws UaException; + + /** + * An asynchronous implementation of {@link #readHighestActiveSeverity}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readHighestActiveSeverityAsync(); + + /** + * An asynchronous implementation of {@link #writeHighestActiveSeverity}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeHighestActiveSeverityAsync(UShort value); + + /** + * Get the HighestActiveSeverity {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the HighestActiveSeverity {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getHighestActiveSeverityNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getHighestActiveSeverityNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getHighestActiveSeverityNodeAsync(); + + /** + * Get the local value of the HighestUnackSeverity Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the HighestUnackSeverity Node. + * @throws UaException if an error occurs creating or getting the HighestUnackSeverity Node. + */ + UShort getHighestUnackSeverity() throws UaException; + + /** + * Set the local value of the HighestUnackSeverity Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the HighestUnackSeverity Node. + * @throws UaException if an error occurs creating or getting the HighestUnackSeverity Node. + */ + void setHighestUnackSeverity(UShort value) throws UaException; + + /** + * Read the value of the HighestUnackSeverity Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link UShort} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + UShort readHighestUnackSeverity() throws UaException; + + /** + * Write a new value for the HighestUnackSeverity Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link UShort} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeHighestUnackSeverity(UShort value) throws UaException; + + /** + * An asynchronous implementation of {@link #readHighestUnackSeverity}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readHighestUnackSeverityAsync(); + + /** + * An asynchronous implementation of {@link #writeHighestUnackSeverity}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeHighestUnackSeverityAsync(UShort value); + + /** + * Get the HighestUnackSeverity {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the HighestUnackSeverity {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getHighestUnackSeverityNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getHighestUnackSeverityNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getHighestUnackSeverityNodeAsync(); + + /** + * Get the local value of the ActiveCount Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ActiveCount Node. + * @throws UaException if an error occurs creating or getting the ActiveCount Node. + */ + UInteger getActiveCount() throws UaException; + + /** + * Set the local value of the ActiveCount Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ActiveCount Node. + * @throws UaException if an error occurs creating or getting the ActiveCount Node. + */ + void setActiveCount(UInteger value) throws UaException; + + /** + * Read the value of the ActiveCount Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link UInteger} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + UInteger readActiveCount() throws UaException; + + /** + * Write a new value for the ActiveCount Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link UInteger} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeActiveCount(UInteger value) throws UaException; + + /** + * An asynchronous implementation of {@link #readActiveCount}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readActiveCountAsync(); + + /** + * An asynchronous implementation of {@link #writeActiveCount}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeActiveCountAsync(UInteger value); + + /** + * Get the ActiveCount {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ActiveCount {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getActiveCountNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getActiveCountNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getActiveCountNodeAsync(); + + /** + * Get the local value of the UnacknowledgedCount Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the UnacknowledgedCount Node. + * @throws UaException if an error occurs creating or getting the UnacknowledgedCount Node. + */ + UInteger getUnacknowledgedCount() throws UaException; + + /** + * Set the local value of the UnacknowledgedCount Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the UnacknowledgedCount Node. + * @throws UaException if an error occurs creating or getting the UnacknowledgedCount Node. + */ + void setUnacknowledgedCount(UInteger value) throws UaException; + + /** + * Read the value of the UnacknowledgedCount Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link UInteger} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + UInteger readUnacknowledgedCount() throws UaException; + + /** + * Write a new value for the UnacknowledgedCount Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link UInteger} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeUnacknowledgedCount(UInteger value) throws UaException; + + /** + * An asynchronous implementation of {@link #readUnacknowledgedCount}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readUnacknowledgedCountAsync(); + + /** + * An asynchronous implementation of {@link #writeUnacknowledgedCount}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeUnacknowledgedCountAsync(UInteger value); + + /** + * Get the UnacknowledgedCount {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the UnacknowledgedCount {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getUnacknowledgedCountNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getUnacknowledgedCountNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getUnacknowledgedCountNodeAsync(); + + /** + * Get the local value of the UnconfirmedCount Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the UnconfirmedCount Node. + * @throws UaException if an error occurs creating or getting the UnconfirmedCount Node. + */ + UInteger getUnconfirmedCount() throws UaException; + + /** + * Set the local value of the UnconfirmedCount Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the UnconfirmedCount Node. + * @throws UaException if an error occurs creating or getting the UnconfirmedCount Node. + */ + void setUnconfirmedCount(UInteger value) throws UaException; + + /** + * Read the value of the UnconfirmedCount Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link UInteger} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + UInteger readUnconfirmedCount() throws UaException; + + /** + * Write a new value for the UnconfirmedCount Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link UInteger} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeUnconfirmedCount(UInteger value) throws UaException; + + /** + * An asynchronous implementation of {@link #readUnconfirmedCount}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readUnconfirmedCountAsync(); + + /** + * An asynchronous implementation of {@link #writeUnconfirmedCount}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeUnconfirmedCountAsync(UInteger value); + + /** + * Get the UnconfirmedCount {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the UnconfirmedCount {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getUnconfirmedCountNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getUnconfirmedCountNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getUnconfirmedCountNodeAsync(); + + /** + * Get the local value of the Filter Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the Filter Node. + * @throws UaException if an error occurs creating or getting the Filter Node. + */ + ContentFilter getFilter() throws UaException; + + /** + * Set the local value of the Filter Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the Filter Node. + * @throws UaException if an error occurs creating or getting the Filter Node. + */ + void setFilter(ContentFilter value) throws UaException; + + /** + * Read the value of the Filter Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link ContentFilter} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + ContentFilter readFilter() throws UaException; + + /** + * Write a new value for the Filter Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link ContentFilter} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeFilter(ContentFilter value) throws UaException; + + /** + * An asynchronous implementation of {@link #readFilter}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readFilterAsync(); + + /** + * An asynchronous implementation of {@link #writeFilter}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeFilterAsync(ContentFilter value); + + /** + * Get the Filter {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the Filter {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getFilterNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getFilterNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getFilterNodeAsync(); +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmStateVariableTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmStateVariableTypeNode.java new file mode 100644 index 000000000..d7523c2ab --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/AlarmStateVariableTypeNode.java @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.variables; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; +import org.eclipse.milo.opcua.sdk.client.nodes.UaNode; +import org.eclipse.milo.opcua.stack.core.AttributeId; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; +import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessLevelExType; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.ContentFilter; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class AlarmStateVariableTypeNode extends BaseDataVariableTypeNode implements AlarmStateVariableType { + public AlarmStateVariableTypeNode(OpcUaClient client, NodeId nodeId, NodeClass nodeClass, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + DataValue value, NodeId dataType, Integer valueRank, UInteger[] arrayDimensions, + UByte accessLevel, UByte userAccessLevel, Double minimumSamplingInterval, Boolean historizing, + AccessLevelExType accessLevelEx) { + super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, value, dataType, valueRank, arrayDimensions, accessLevel, userAccessLevel, minimumSamplingInterval, historizing, accessLevelEx); + } + + @Override + public UShort getHighestActiveSeverity() throws UaException { + PropertyTypeNode node = getHighestActiveSeverityNode(); + return (UShort) node.getValue().getValue().getValue(); + } + + @Override + public void setHighestActiveSeverity(UShort value) throws UaException { + PropertyTypeNode node = getHighestActiveSeverityNode(); + node.setValue(new Variant(value)); + } + + @Override + public UShort readHighestActiveSeverity() throws UaException { + try { + return readHighestActiveSeverityAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeHighestActiveSeverity(UShort value) throws UaException { + try { + writeHighestActiveSeverityAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readHighestActiveSeverityAsync() { + return getHighestActiveSeverityNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (UShort) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeHighestActiveSeverityAsync( + UShort highestActiveSeverity) { + DataValue value = DataValue.valueOnly(new Variant(highestActiveSeverity)); + return getHighestActiveSeverityNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getHighestActiveSeverityNode() throws UaException { + try { + return getHighestActiveSeverityNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getHighestActiveSeverityNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "HighestActiveSeverity", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public UShort getHighestUnackSeverity() throws UaException { + PropertyTypeNode node = getHighestUnackSeverityNode(); + return (UShort) node.getValue().getValue().getValue(); + } + + @Override + public void setHighestUnackSeverity(UShort value) throws UaException { + PropertyTypeNode node = getHighestUnackSeverityNode(); + node.setValue(new Variant(value)); + } + + @Override + public UShort readHighestUnackSeverity() throws UaException { + try { + return readHighestUnackSeverityAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeHighestUnackSeverity(UShort value) throws UaException { + try { + writeHighestUnackSeverityAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readHighestUnackSeverityAsync() { + return getHighestUnackSeverityNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (UShort) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeHighestUnackSeverityAsync(UShort highestUnackSeverity) { + DataValue value = DataValue.valueOnly(new Variant(highestUnackSeverity)); + return getHighestUnackSeverityNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getHighestUnackSeverityNode() throws UaException { + try { + return getHighestUnackSeverityNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getHighestUnackSeverityNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "HighestUnackSeverity", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public UInteger getActiveCount() throws UaException { + PropertyTypeNode node = getActiveCountNode(); + return (UInteger) node.getValue().getValue().getValue(); + } + + @Override + public void setActiveCount(UInteger value) throws UaException { + PropertyTypeNode node = getActiveCountNode(); + node.setValue(new Variant(value)); + } + + @Override + public UInteger readActiveCount() throws UaException { + try { + return readActiveCountAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeActiveCount(UInteger value) throws UaException { + try { + writeActiveCountAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readActiveCountAsync() { + return getActiveCountNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (UInteger) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeActiveCountAsync(UInteger activeCount) { + DataValue value = DataValue.valueOnly(new Variant(activeCount)); + return getActiveCountNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getActiveCountNode() throws UaException { + try { + return getActiveCountNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getActiveCountNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ActiveCount", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public UInteger getUnacknowledgedCount() throws UaException { + PropertyTypeNode node = getUnacknowledgedCountNode(); + return (UInteger) node.getValue().getValue().getValue(); + } + + @Override + public void setUnacknowledgedCount(UInteger value) throws UaException { + PropertyTypeNode node = getUnacknowledgedCountNode(); + node.setValue(new Variant(value)); + } + + @Override + public UInteger readUnacknowledgedCount() throws UaException { + try { + return readUnacknowledgedCountAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeUnacknowledgedCount(UInteger value) throws UaException { + try { + writeUnacknowledgedCountAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readUnacknowledgedCountAsync() { + return getUnacknowledgedCountNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (UInteger) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeUnacknowledgedCountAsync(UInteger unacknowledgedCount) { + DataValue value = DataValue.valueOnly(new Variant(unacknowledgedCount)); + return getUnacknowledgedCountNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getUnacknowledgedCountNode() throws UaException { + try { + return getUnacknowledgedCountNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getUnacknowledgedCountNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "UnacknowledgedCount", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public UInteger getUnconfirmedCount() throws UaException { + PropertyTypeNode node = getUnconfirmedCountNode(); + return (UInteger) node.getValue().getValue().getValue(); + } + + @Override + public void setUnconfirmedCount(UInteger value) throws UaException { + PropertyTypeNode node = getUnconfirmedCountNode(); + node.setValue(new Variant(value)); + } + + @Override + public UInteger readUnconfirmedCount() throws UaException { + try { + return readUnconfirmedCountAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeUnconfirmedCount(UInteger value) throws UaException { + try { + writeUnconfirmedCountAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readUnconfirmedCountAsync() { + return getUnconfirmedCountNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> (UInteger) v.getValue().getValue()); + } + + @Override + public CompletableFuture writeUnconfirmedCountAsync(UInteger unconfirmedCount) { + DataValue value = DataValue.valueOnly(new Variant(unconfirmedCount)); + return getUnconfirmedCountNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getUnconfirmedCountNode() throws UaException { + try { + return getUnconfirmedCountNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getUnconfirmedCountNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "UnconfirmedCount", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } + + @Override + public ContentFilter getFilter() throws UaException { + PropertyTypeNode node = getFilterNode(); + return cast(node.getValue().getValue().getValue(), ContentFilter.class); + } + + @Override + public void setFilter(ContentFilter value) throws UaException { + PropertyTypeNode node = getFilterNode(); + ExtensionObject encoded = ExtensionObject.encode(client.getStaticEncodingContext(), value); + node.setValue(new Variant(encoded)); + } + + @Override + public ContentFilter readFilter() throws UaException { + try { + return readFilterAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeFilter(ContentFilter value) throws UaException { + try { + writeFilterAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readFilterAsync() { + return getFilterNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> cast(v.getValue().getValue(), ContentFilter.class)); + } + + @Override + public CompletableFuture writeFilterAsync(ContentFilter filter) { + ExtensionObject encoded = ExtensionObject.encode(client.getStaticEncodingContext(), filter); + DataValue value = DataValue.valueOnly(new Variant(encoded)); + return getFilterNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getFilterNode() throws UaException { + try { + return getFilterNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getFilterNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "Filter", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/ReferenceDescriptionVariableType.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/ReferenceDescriptionVariableType.java new file mode 100644 index 000000000..a69ee0be8 --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/ReferenceDescriptionVariableType.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.variables; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceListEntryDataType; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part23/5.3.1 + */ +public interface ReferenceDescriptionVariableType extends BaseDataVariableType { + QualifiedProperty REFERENCE_REFINEMENT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ReferenceRefinement", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=32660"), + 1, + ReferenceListEntryDataType[].class + ); + + /** + * Get the local value of the ReferenceRefinement Node. + *

+ * The returned value is the last seen; it is not read live from the server. + * + * @return the local value of the ReferenceRefinement Node. + * @throws UaException if an error occurs creating or getting the ReferenceRefinement Node. + */ + ReferenceListEntryDataType[] getReferenceRefinement() throws UaException; + + /** + * Set the local value of the ReferenceRefinement Node. + *

+ * The value is only updated locally; it is not written to the server. + * + * @param value the local value to set for the ReferenceRefinement Node. + * @throws UaException if an error occurs creating or getting the ReferenceRefinement Node. + */ + void setReferenceRefinement(ReferenceListEntryDataType[] value) throws UaException; + + /** + * Read the value of the ReferenceRefinement Node from the server and update the local value if + * the operation succeeds. + * + * @return the {@link ReferenceListEntryDataType[]} value read from the server. + * @throws UaException if a service- or operation-level error occurs. + */ + ReferenceListEntryDataType[] readReferenceRefinement() throws UaException; + + /** + * Write a new value for the ReferenceRefinement Node to the server and update the local value if + * the operation succeeds. + * + * @param value the {@link ReferenceListEntryDataType[]} value to write to the server. + * @throws UaException if a service- or operation-level error occurs. + */ + void writeReferenceRefinement(ReferenceListEntryDataType[] value) throws UaException; + + /** + * An asynchronous implementation of {@link #readReferenceRefinement}. + * + * @return a CompletableFuture that completes successfully with the value or completes + * exceptionally if an operation- or service-level error occurs. + */ + CompletableFuture readReferenceRefinementAsync(); + + /** + * An asynchronous implementation of {@link #writeReferenceRefinement}. + * + * @return a CompletableFuture that completes successfully with the operation result or + * completes exceptionally if a service-level error occurs. + */ + CompletableFuture writeReferenceRefinementAsync(ReferenceListEntryDataType[] value); + + /** + * Get the ReferenceRefinement {@link PropertyType} Node, or {@code null} if it does not exist. + *

+ * The Node is created when first accessed and cached for subsequent calls. + * + * @return the ReferenceRefinement {@link PropertyType} Node, or {@code null} if it does not exist. + * @throws UaException if an error occurs creating or getting the Node. + */ + PropertyType getReferenceRefinementNode() throws UaException; + + /** + * Asynchronous implementation of {@link #getReferenceRefinementNode()}. + * + * @return a CompletableFuture that completes successfully with the + * PropertyType Node or completes exceptionally if an error occurs creating or + * getting the Node. + */ + CompletableFuture getReferenceRefinementNodeAsync(); +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/ReferenceDescriptionVariableTypeNode.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/ReferenceDescriptionVariableTypeNode.java new file mode 100644 index 000000000..9016cd8db --- /dev/null +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/model/variables/ReferenceDescriptionVariableTypeNode.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.client.model.variables; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; +import org.eclipse.milo.opcua.sdk.client.nodes.UaNode; +import org.eclipse.milo.opcua.stack.core.AttributeId; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessLevelExType; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceListEntryDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class ReferenceDescriptionVariableTypeNode extends BaseDataVariableTypeNode implements ReferenceDescriptionVariableType { + public ReferenceDescriptionVariableTypeNode(OpcUaClient client, NodeId nodeId, + NodeClass nodeClass, QualifiedName browseName, LocalizedText displayName, + LocalizedText description, UInteger writeMask, UInteger userWriteMask, + RolePermissionType[] rolePermissions, RolePermissionType[] userRolePermissions, + AccessRestrictionType accessRestrictions, DataValue value, NodeId dataType, Integer valueRank, + UInteger[] arrayDimensions, UByte accessLevel, UByte userAccessLevel, + Double minimumSamplingInterval, Boolean historizing, AccessLevelExType accessLevelEx) { + super(client, nodeId, nodeClass, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, value, dataType, valueRank, arrayDimensions, accessLevel, userAccessLevel, minimumSamplingInterval, historizing, accessLevelEx); + } + + @Override + public ReferenceListEntryDataType[] getReferenceRefinement() throws UaException { + PropertyTypeNode node = getReferenceRefinementNode(); + return cast(node.getValue().getValue().getValue(), ReferenceListEntryDataType[].class); + } + + @Override + public void setReferenceRefinement(ReferenceListEntryDataType[] value) throws UaException { + PropertyTypeNode node = getReferenceRefinementNode(); + ExtensionObject[] encoded = ExtensionObject.encodeArray(client.getStaticEncodingContext(), value); + node.setValue(new Variant(encoded)); + } + + @Override + public ReferenceListEntryDataType[] readReferenceRefinement() throws UaException { + try { + return readReferenceRefinementAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public void writeReferenceRefinement(ReferenceListEntryDataType[] value) throws UaException { + try { + writeReferenceRefinementAsync(value).get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); + } + } + + @Override + public CompletableFuture readReferenceRefinementAsync() { + return getReferenceRefinementNodeAsync() + .thenCompose(node -> node.readAttributeAsync(AttributeId.Value)) + .thenApply(v -> cast(v.getValue().getValue(), ReferenceListEntryDataType[].class)); + } + + @Override + public CompletableFuture writeReferenceRefinementAsync( + ReferenceListEntryDataType[] referenceRefinement) { + ExtensionObject[] encoded = ExtensionObject.encodeArray(client.getStaticEncodingContext(), referenceRefinement); + DataValue value = DataValue.valueOnly(new Variant(encoded)); + return getReferenceRefinementNodeAsync() + .thenCompose(node -> node.writeAttributeAsync(AttributeId.Value, value)); + } + + @Override + public PropertyTypeNode getReferenceRefinementNode() throws UaException { + try { + return getReferenceRefinementNodeAsync().get(); + } catch (ExecutionException | InterruptedException e) { + throw UaException.extract(e).orElse(new UaException(StatusCodes.Bad_UnexpectedError)); + } + } + + @Override + public CompletableFuture getReferenceRefinementNodeAsync() { + CompletableFuture future = getMemberNodeAsync( + "http://opcfoundation.org/UA/", + "ReferenceRefinement", + ExpandedNodeId.parse("ns=0;i=46"), + false + ); + return future.thenApply(node -> (PropertyTypeNode) node); + } +} diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsm.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsm.java index 11c9ccd0f..f1e58acfd 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsm.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -17,16 +17,15 @@ import com.digitalpetri.strictmachine.Fsm; import com.digitalpetri.strictmachine.FsmContext; +import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.sdk.client.OpcUaSession; import org.eclipse.milo.opcua.sdk.client.SessionActivityListener; -import org.eclipse.milo.opcua.stack.client.UaStackClient; import org.eclipse.milo.opcua.stack.core.util.Unit; public class SessionFsm { static final String LOGGER_NAME = "org.eclipse.milo.opcua.sdk.client.SessionFsm"; - private final List sessionInitializers; private final List sessionActivityListeners; @@ -155,7 +154,7 @@ private SessionActivityListeners() {} public interface SessionInitializer { - CompletableFuture initialize(UaStackClient stackClient, OpcUaSession session); + CompletableFuture initialize(OpcUaClient client, OpcUaSession session); } diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsmFactory.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsmFactory.java index 1e8ecdddb..e9aa1d4b5 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsmFactory.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsmFactory.java @@ -39,9 +39,6 @@ import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscription; import org.eclipse.milo.opcua.sdk.client.session.SessionFsm.SessionFuture; import org.eclipse.milo.opcua.sdk.client.subscriptions.OpcUaSubscriptionManager; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.transport.UaTransport; -import org.eclipse.milo.opcua.stack.client.transport.tcp.OpcTcpTransport; import org.eclipse.milo.opcua.stack.core.AttributeId; import org.eclipse.milo.opcua.stack.core.NodeIds; import org.eclipse.milo.opcua.stack.core.StatusCodes; @@ -80,6 +77,8 @@ import org.eclipse.milo.opcua.stack.core.util.NonceUtil; import org.eclipse.milo.opcua.stack.core.util.SignatureUtil; import org.eclipse.milo.opcua.stack.core.util.Unit; +import org.eclipse.milo.opcua.stack.transport.client.OpcClientTransport; +import org.eclipse.milo.opcua.stack.transport.client.tcp.OpcTcpClientTransport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -108,7 +107,7 @@ private SessionFsmFactory() {} public static SessionFsm newSessionFsm(OpcUaClient client) { FsmBuilder builder = new FsmBuilder<>( - client.getConfig().getExecutor(), + client.getTransport().getConfig().getExecutor(), SessionFsm.LOGGER_NAME ); @@ -158,7 +157,7 @@ private static void configureInactiveState( .execute(ctx -> { Event.GetSession event = (Event.GetSession) ctx.event(); - client.getConfig().getExecutor().execute(() -> + client.getTransport().getConfig().getExecutor().execute(() -> event.future.completeExceptionally( new UaException(StatusCodes.Bad_SessionClosed)) ); @@ -169,7 +168,7 @@ private static void configureInactiveState( .execute(ctx -> { Event.CloseSession event = (Event.CloseSession) ctx.event(); - client.getConfig().getExecutor().execute(() -> + client.getTransport().getConfig().getExecutor().execute(() -> event.future.complete(Unit.VALUE) ); }); @@ -212,7 +211,7 @@ private static void configureCreatingWaitState( } KEY_WAIT_TIME.set(ctx, waitTime); - ScheduledFuture waitFuture = client.getConfig().getScheduledExecutor().schedule( + ScheduledFuture waitFuture = client.getTransport().getConfig().getScheduledExecutor().schedule( () -> ctx.fireEvent(new Event.CreatingWaitExpired()), waitTime, TimeUnit.SECONDS @@ -231,7 +230,7 @@ private static void configureCreatingWaitState( Event.CloseSession event = (Event.CloseSession) ctx.event(); - client.getConfig().getExecutor().execute(() -> + client.getTransport().getConfig().getExecutor().execute(() -> event.future.complete(Unit.VALUE) ); }); @@ -520,7 +519,7 @@ private static void configureActiveState(FsmBuilder fb, OpcUaClien long keepAliveInterval = client.getConfig().getKeepAliveInterval().longValue(); KEY_KEEP_ALIVE_FAILURE_COUNT.set(ctx, 0L); - ScheduledFuture scheduledFuture = client.getConfig().getScheduledExecutor().scheduleWithFixedDelay( + ScheduledFuture scheduledFuture = client.getTransport().getConfig().getScheduledExecutor().scheduleWithFixedDelay( () -> ctx.fireEvent(new Event.KeepAlive(event.session)), keepAliveInterval, keepAliveInterval, @@ -532,10 +531,10 @@ private static void configureActiveState(FsmBuilder fb, OpcUaClien SessionFuture sessionFuture = KEY_SESSION_FUTURE.get(ctx); - UaTransport transport = client.getStackClient().getTransport(); + OpcClientTransport transport = client.getTransport(); - if (transport instanceof OpcTcpTransport) { - ChannelFsm channelFsm = ((OpcTcpTransport) transport).channelFsm(); + if (transport instanceof OpcTcpClientTransport) { + ChannelFsm channelFsm = ((OpcTcpClientTransport) transport).getChannelFsm(); channelFsm.addTransitionListener(new ChannelFsm.TransitionListener() { @Override @@ -559,7 +558,7 @@ public void onStateTransition( }); } - client.getConfig().getExecutor().execute(() -> + client.getTransport().getConfig().getExecutor().execute(() -> sessionFuture.future.complete(event.session) ); }); @@ -709,7 +708,7 @@ private static void configureClosingState(FsmBuilder fb, OpcUaClie SessionFsm.CloseFuture closeFuture = KEY_CLOSE_FUTURE.get(ctx); if (closeFuture != null) { - client.getConfig().getExecutor().execute(() -> + client.getTransport().getConfig().getExecutor().execute(() -> closeFuture.future.complete(Unit.VALUE) ); } @@ -759,7 +758,7 @@ private static void handleFailureToOpenSession( SessionFuture sessionFuture = KEY_SESSION_FUTURE.remove(ctx); if (sessionFuture != null) { - client.getConfig().getExecutor().execute(() -> + client.getTransport().getConfig().getExecutor().execute(() -> sessionFuture.future.completeExceptionally(failure) ); } @@ -768,13 +767,12 @@ private static void handleFailureToOpenSession( private static CompletableFuture closeSession( FsmContext ctx, OpcUaClient client, - OpcUaSession session) { + OpcUaSession session + ) { CompletableFuture closeFuture = new CompletableFuture<>(); - UaStackClient stackClient = client.getStackClient(); - - RequestHeader requestHeader = stackClient.newRequestHeader( + RequestHeader requestHeader = client.newRequestHeader( session.getAuthenticationToken(), uint(5000) ); @@ -783,13 +781,13 @@ private static CompletableFuture closeSession( LOGGER.debug("[{}] Sending CloseSessionRequest...", ctx.getInstanceId()); - stackClient.sendRequest(request).whenCompleteAsync( + client.getTransport().sendRequestMessage(request).whenCompleteAsync( (csr, ex2) -> { client.getSubscriptionManager().cancelWatchdogTimers(); closeFuture.complete(Unit.VALUE); }, - client.getConfig().getExecutor() + client.getTransport().getConfig().getExecutor() ); return closeFuture; @@ -798,11 +796,10 @@ private static CompletableFuture closeSession( @SuppressWarnings("Duplicates") private static CompletableFuture createSession( FsmContext ctx, - OpcUaClient client) { - - UaStackClient stackClient = client.getStackClient(); + OpcUaClient client + ) { - EndpointDescription endpoint = stackClient.getConfig().getEndpoint(); + EndpointDescription endpoint = client.getConfig().getEndpoint(); String gatewayServerUri = endpoint.getServer().getGatewayServerUri(); @@ -815,7 +812,7 @@ private static CompletableFuture createSession( ByteString clientNonce = NonceUtil.generateNonce(32); - ByteString clientCertificate = stackClient.getConfig().getCertificate() + ByteString clientCertificate = client.getConfig().getCertificate() .map(c -> { try { return ByteString.of(c.getEncoded()); @@ -849,7 +846,8 @@ private static CompletableFuture createSession( LOGGER.debug("[{}] Sending CreateSessionRequest...", ctx.getInstanceId()); - return stackClient.sendRequest(request) + return client.getTransport() + .sendRequestMessage(request) .thenApply(CreateSessionResponse.class::cast) .thenCompose(response -> { try { @@ -910,9 +908,8 @@ private static CompletableFuture createSession( private static CompletableFuture activateSession( FsmContext ctx, OpcUaClient client, - CreateSessionResponse csr) { - - UaStackClient stackClient = client.getStackClient(); + CreateSessionResponse csr + ) { try { EndpointDescription endpoint = client.getConfig().getEndpoint(); @@ -937,7 +934,8 @@ private static CompletableFuture activateSession( LOGGER.debug("[{}] Sending ActivateSessionRequest...", ctx.getInstanceId()); - return stackClient.sendRequest(request) + return client.getTransport() + .sendRequestMessage(request) .thenApply(ActivateSessionResponse.class::cast) .thenCompose(asr -> { ByteString asrNonce = asr.getServerNonce(); @@ -967,9 +965,9 @@ private static CompletableFuture activateSession( private static CompletableFuture transferSubscriptions( FsmContext ctx, OpcUaClient client, - OpcUaSession session) { + OpcUaSession session + ) { - UaStackClient stackClient = client.getStackClient(); OpcUaSubscriptionManager subscriptionManager = client.getSubscriptionManager(); List subscriptions = subscriptionManager.getSubscriptions(); @@ -991,7 +989,8 @@ private static CompletableFuture transferSubscriptions( LOGGER.debug("[{}] Sending TransferSubscriptionsRequest...", ctx.getInstanceId()); - stackClient.sendRequest(request) + client.getTransport() + .sendRequestMessage(request) .thenApply(TransferSubscriptionsResponse.class::cast) .whenComplete((tsr, ex) -> { if (tsr != null) { @@ -1025,7 +1024,7 @@ private static CompletableFuture transferSubscriptions( } } - client.getConfig().getExecutor().execute(() -> { + client.getTransport().getConfig().getExecutor().execute(() -> { for (int i = 0; i < results.size(); i++) { TransferResult result = results.get(i); @@ -1048,7 +1047,7 @@ private static CompletableFuture transferSubscriptions( LOGGER.debug("[{}] TransferSubscriptions not supported: {}", ctx.getInstanceId(), statusCode); - client.getConfig().getExecutor().execute(() -> { + client.getTransport().getConfig().getExecutor().execute(() -> { // transferFailed() will remove the subscription, but that is okay // because the list from getSubscriptions() above is a copy. for (UaSubscription subscription : subscriptions) { @@ -1096,14 +1095,12 @@ private static CompletableFuture initialize( if (initializers.isEmpty()) { return completedFuture(Unit.VALUE); } else { - UaStackClient stackClient = client.getStackClient(); - - return runSequentially(stackClient, session, initializers); + return runSequentially(client, session, initializers); } } private static CompletableFuture runSequentially( - UaStackClient client, + OpcUaClient client, OpcUaSession session, LinkedList initializers ) { @@ -1126,13 +1123,13 @@ private static CompletableFuture runSequentially( private static CompletableFuture sendKeepAlive(OpcUaClient client, OpcUaSession session) { ReadRequest keepAliveRequest = createKeepAliveRequest(client, session); - return client.getStackClient() - .sendRequest(keepAliveRequest) + return client.getTransport() + .sendRequestMessage(keepAliveRequest) .thenApply(ReadResponse.class::cast); } private static ReadRequest createKeepAliveRequest(OpcUaClient client, OpcUaSession session) { - RequestHeader requestHeader = client.getStackClient().newRequestHeader( + RequestHeader requestHeader = client.newRequestHeader( session.getAuthenticationToken(), client.getConfig().getKeepAliveTimeout() ); diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/subscriptions/ManagedSubscription.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/subscriptions/ManagedSubscription.java index bd6149dfd..e4693f89b 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/subscriptions/ManagedSubscription.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/subscriptions/ManagedSubscription.java @@ -1232,7 +1232,8 @@ default void onSubscriptionWatchdogTimerElapsed(ManagedSubscription subscription */ private class ManagedSubscriptionNotificationListener implements UaSubscription.NotificationListener { - private final ExecutionQueue executionQueue = new ExecutionQueue(client.getConfig().getExecutor()); + private final ExecutionQueue executionQueue = + new ExecutionQueue(client.getTransport().getConfig().getExecutor()); //region UaSubscription.NotificationListener diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/subscriptions/OpcUaSubscriptionManager.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/subscriptions/OpcUaSubscriptionManager.java index dc4ae1dae..808c8c83d 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/subscriptions/OpcUaSubscriptionManager.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/subscriptions/OpcUaSubscriptionManager.java @@ -89,8 +89,8 @@ public class OpcUaSubscriptionManager implements UaSubscriptionManager { public OpcUaSubscriptionManager(OpcUaClient client) { this.client = client; - deliveryQueue = new ExecutionQueue(client.getConfig().getExecutor()); - processingQueue = new ExecutionQueue(client.getConfig().getExecutor()); + deliveryQueue = new ExecutionQueue(client.getTransport().getConfig().getExecutor()); + processingQueue = new ExecutionQueue(client.getTransport().getConfig().getExecutor()); client.addSessionActivityListener(new SessionActivityListener() { @Override @@ -483,7 +483,7 @@ private void sendPublishRequest(UaSession session, AtomicLong pendingCount) { } }); - RequestHeader requestHeader = client.getStackClient().newRequestHeader( + RequestHeader requestHeader = client.newRequestHeader( session.getAuthenticationToken(), getTimeoutHint() ); @@ -506,12 +506,13 @@ private void sendPublishRequest(UaSession session, AtomicLong pendingCount) { requestHandle, Arrays.toString(ackStrings)); } - client.sendRequest(request).whenComplete((response, ex) -> { - if (response != null) { + client.getTransport().sendRequestMessage(request).whenComplete((response, ex) -> { + if (response instanceof PublishResponse) { + PublishResponse publishResponse = (PublishResponse) response; logger.debug("Received PublishResponse, sequenceNumber={}", - response.getNotificationMessage().getSequenceNumber()); + publishResponse.getNotificationMessage().getSequenceNumber()); - processingQueue.submit(() -> onPublishComplete(response, pendingCount)); + processingQueue.submit(() -> onPublishComplete(publishResponse, pendingCount)); } else { StatusCode statusCode = UaException.extract(ex) .map(UaException::getStatusCode) @@ -623,7 +624,7 @@ private void onPublishComplete(PublishResponse response, AtomicLong pendingCount maybeSendPublishRequests(); }, - client.getConfig().getExecutor() + client.getTransport().getConfig().getExecutor() ); } @@ -883,8 +884,8 @@ private void scheduleNext() { long delay = Math.round(subscription.getRevisedPublishingInterval() * subscription.getRevisedMaxKeepAliveCount().longValue() * multiplier); - ScheduledFuture nextSf = client.getConfig().getScheduledExecutor().schedule( - () -> client.getConfig().getExecutor().execute(this::notifyListeners), + ScheduledFuture nextSf = client.getTransport().getConfig().getScheduledExecutor().schedule( + () -> client.getTransport().getConfig().getExecutor().execute(this::notifyListeners), delay, TimeUnit.MILLISECONDS ); diff --git a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/typetree/DataTypeTreeBuilder.java b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/typetree/DataTypeTreeBuilder.java index f8807feb0..2f07b7859 100644 --- a/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/typetree/DataTypeTreeBuilder.java +++ b/opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/typetree/DataTypeTreeBuilder.java @@ -21,7 +21,6 @@ import org.eclipse.milo.opcua.sdk.client.OpcUaSession; import org.eclipse.milo.opcua.sdk.core.typetree.DataType; import org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree; -import org.eclipse.milo.opcua.stack.client.UaStackClient; import org.eclipse.milo.opcua.stack.core.AttributeId; import org.eclipse.milo.opcua.stack.core.NamespaceTable; import org.eclipse.milo.opcua.stack.core.NodeIds; @@ -86,12 +85,12 @@ public static DataTypeTree build(OpcUaClient client) throws UaException { * Build a {@link DataTypeTree} by recursively browsing the DataType hierarchy starting at * {@link NodeIds#BaseDataType}. * - * @param client a connected {@link UaStackClient}. + * @param client a connected {@link OpcUaClient}. * @param session an active {@link OpcUaSession}. * @return a {@link DataTypeTree}. * @throws UaException if an unrecoverable error occurs while building the tree. */ - public static DataTypeTree build(UaStackClient client, OpcUaSession session) throws UaException { + public static DataTypeTree build(OpcUaClient client, OpcUaSession session) throws UaException { try { return buildAsync(client, session).get(); } catch (InterruptedException e) { @@ -112,7 +111,7 @@ public static DataTypeTree build(UaStackClient client, OpcUaSession session) thr public static CompletableFuture buildAsync(OpcUaClient client) { return client.getSession().thenCompose( session -> - buildAsync(client.getStackClient(), session) + buildAsync(client, session) ); } @@ -120,11 +119,11 @@ public static CompletableFuture buildAsync(OpcUaClient client) { * Build a {@link DataTypeTree} by recursively browsing the DataType hierarchy starting at * {@link NodeIds#BaseDataType}. * - * @param client a connected {@link UaStackClient}. + * @param client a connected {@link OpcUaClient}. * @param session an active {@link OpcUaSession}. * @return a {@link DataTypeTree}. */ - public static CompletableFuture buildAsync(UaStackClient client, OpcUaSession session) { + public static CompletableFuture buildAsync(OpcUaClient client, OpcUaSession session) { Tree root = new Tree<>( null, new ClientDataType( @@ -142,13 +141,13 @@ public static CompletableFuture buildAsync(UaStackClient client, O .thenApply(u -> new DataTypeTree(root)); } - private static CompletableFuture readNamespaceTable(UaStackClient client, OpcUaSession session) { + private static CompletableFuture readNamespaceTable(OpcUaClient client, OpcUaSession session) { RequestHeader requestHeader = client.newRequestHeader( session.getAuthenticationToken(), client.getConfig().getRequestTimeout() ); - CompletableFuture readFuture = client.sendRequest( + CompletableFuture readFuture = client.getTransport().sendRequestMessage( new ReadRequest( requestHeader, 0.0, @@ -177,7 +176,7 @@ private static CompletableFuture readNamespaceTable(UaStackClien private static CompletableFuture addChildren( Tree tree, - UaStackClient client, + OpcUaClient client, OpcUaSession session, NamespaceTable namespaceTable ) { @@ -265,13 +264,13 @@ private static CompletableFuture addChildren( * Browse a {@link BrowseDescription} "safely", completing successfully * with an empty List if any exceptions occur. * - * @param client a {@link UaStackClient}. + * @param client an {@link OpcUaClient}. * @param session an {@link OpcUaSession}. * @param browseDescription the {@link BrowseDescription}. * @return a List of {@link ReferenceDescription}s obtained by browsing {@code browseDescription}. */ private static CompletableFuture> browseSafe( - UaStackClient client, + OpcUaClient client, OpcUaSession session, BrowseDescription browseDescription ) { @@ -283,14 +282,14 @@ private static CompletableFuture> browseSafe( /** * Read the DataTypeDefinition attribute for the DataType Node identified by {@code nodeId}. * - * @param client a {@link UaStackClient}. + * @param client an {@link OpcUaClient}. * @param session an {@link OpcUaSession}. * @param dataTypeId the {@link NodeId} of the DataType node. * @return the value of the {@link DataTypeDefinition} attribute for the Node identified by * {@code dataTypeId}. May be {@code null}. */ private static CompletableFuture<@Nullable DataTypeDefinition> readDataTypeDefinition( - UaStackClient client, + OpcUaClient client, OpcUaSession session, NodeId dataTypeId ) { @@ -312,7 +311,7 @@ private static CompletableFuture> browseSafe( } ); - return client.sendRequest(request) + return client.getTransport().sendRequestMessage(request) .thenApply(ReadResponse.class::cast) .thenApply(response -> { DataValue value = response.getResults()[0]; diff --git a/opc-ua-sdk/sdk-server/pom.xml b/opc-ua-sdk/sdk-server/pom.xml index 93b41eb38..78c9c98f9 100644 --- a/opc-ua-sdk/sdk-server/pom.xml +++ b/opc-ua-sdk/sdk-server/pom.xml @@ -9,7 +9,8 @@ ~ SPDX-License-Identifier: EPL-2.0 --> - + 4.0.0 @@ -30,19 +31,16 @@ stack-core ${project.version} - org.eclipse.milo - stack-server + transport ${project.version} - org.eclipse.milo sdk-core ${project.version} - org.jetbrains annotations diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/AbstractServiceHandler.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/AbstractServiceHandler.java new file mode 100644 index 000000000..56f49c977 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/AbstractServiceHandler.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; + +import org.eclipse.milo.opcua.sdk.server.services.AttributeServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.DiscoveryServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.MethodServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.MonitoredItemServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.NodeManagementServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.Service; +import org.eclipse.milo.opcua.sdk.server.services.SessionServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.SubscriptionServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.ViewServiceSet; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CallRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CancelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSubscriptionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteSubscriptionsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersOnNetworkRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifyMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifySubscriptionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServer2Request; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RepublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetMonitoringModeRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetPublishingModeRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteRequest; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; +import org.jetbrains.annotations.Nullable; + +public abstract class AbstractServiceHandler { + + private final ServiceHandlerTable serviceHandlerTable = new ServiceHandlerTable(); + + public void addServiceSet(String path, AttributeServiceSet serviceSet) { + serviceHandlerTable.put( + path, + Service.ATTRIBUTE_READ, + (context, request) -> + serviceSet.onRead(context, (ReadRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.ATTRIBUTE_HISTORY_READ, + (context, request) -> + serviceSet.onHistoryRead(context, (HistoryReadRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.ATTRIBUTE_WRITE, + (context, request) -> + serviceSet.onWrite(context, (WriteRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.ATTRIBUTE_HISTORY_UPDATE, + (context, request) -> + serviceSet.onHistoryUpdate(context, (HistoryUpdateRequest) request).thenApply(Function.identity()) + ); + } + + public void addServiceSet(String path, DiscoveryServiceSet serviceSet) { + serviceHandlerTable.put( + path, + Service.DISCOVERY_FIND_SERVERS, + (context, request) -> + serviceSet.onFindServers(context, (FindServersRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.DISCOVERY_FIND_SERVERS_ON_NETWORK, + (context, request) -> + serviceSet.onFindServersOnNetwork(context, (FindServersOnNetworkRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.DISCOVERY_GET_ENDPOINTS, + (context, request) -> + serviceSet.onGetEndpoints(context, (GetEndpointsRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.DISCOVERY_REGISTER_SERVER, + (context, request) -> + serviceSet.onRegisterServer(context, (RegisterServerRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.DISCOVERY_REGISTER_SERVER_2, + (context, request) -> + serviceSet.onRegisterServer2(context, (RegisterServer2Request) request).thenApply(Function.identity()) + ); + } + + public void addServiceSet(String path, MethodServiceSet serviceSet) { + serviceHandlerTable.put( + path, + Service.METHOD_CALL, + (context, request) -> + serviceSet.onCall(context, (CallRequest) request).thenApply(Function.identity()) + ); + } + + public void addServiceSet(String path, MonitoredItemServiceSet serviceSet) { + serviceHandlerTable.put( + path, + Service.MONITORED_ITEM_CREATE_MONITORED_ITEMS, + (context, request) -> + serviceSet.onCreateMonitoredItems(context, (CreateMonitoredItemsRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.MONITORED_ITEM_MODIFY_MONITORED_ITEMS, + (context, request) -> + serviceSet.onModifyMonitoredItems(context, (ModifyMonitoredItemsRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.MONITORED_ITEM_DELETE_MONITORED_ITEMS, + (context, request) -> + serviceSet.onDeleteMonitoredItems(context, (DeleteMonitoredItemsRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.MONITORED_ITEM_SET_MONITORING_MODE, + (context, request) -> + serviceSet.onSetMonitoringMode(context, (SetMonitoringModeRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.MONITORED_ITEM_SET_TRIGGERING, + (context, request) -> + serviceSet.onSetTriggering(context, (SetTriggeringRequest) request).thenApply(Function.identity()) + ); + } + + public void addServiceSet(String path, NodeManagementServiceSet serviceSet) { + serviceHandlerTable.put( + path, + Service.NODE_MANAGEMENT_ADD_NODES, + (context, request) -> + serviceSet.onAddNodes(context, (AddNodesRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.NODE_MANAGEMENT_DELETE_NODES, + (context, request) -> + serviceSet.onDeleteNodes(context, (DeleteNodesRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.NODE_MANAGEMENT_ADD_REFERENCES, + (context, request) -> + serviceSet.onAddReferences(context, (AddReferencesRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.NODE_MANAGEMENT_DELETE_REFERENCES, + (context, request) -> + serviceSet.onDeleteReferences(context, (DeleteReferencesRequest) request).thenApply(Function.identity()) + ); + } + + public void addServiceSet(String path, SessionServiceSet serviceSet) { + serviceHandlerTable.put( + path, + Service.SESSION_CREATE_SESSION, + (context, request) -> + serviceSet.onCreateSession(context, (CreateSessionRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.SESSION_ACTIVATE_SESSION, + (context, request) -> + serviceSet.onActivateSession(context, (ActivateSessionRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.SESSION_CLOSE_SESSION, + (context, request) -> + serviceSet.onCloseSession(context, (CloseSessionRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.SESSION_CANCEL, + (context, request) -> + serviceSet.onCancel(context, (CancelRequest) request).thenApply(Function.identity()) + ); + } + + public void addServiceSet(String path, SubscriptionServiceSet serviceSet) { + serviceHandlerTable.put( + path, + Service.SUBSCRIPTION_CREATE_SUBSCRIPTION, + (context, request) -> + serviceSet.onCreateSubscription(context, (CreateSubscriptionRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.SUBSCRIPTION_MODIFY_SUBSCRIPTION, + (context, request) -> + serviceSet.onModifySubscription(context, (ModifySubscriptionRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.SUBSCRIPTION_DELETE_SUBSCRIPTIONS, + (context, request) -> + serviceSet.onDeleteSubscriptions(context, (DeleteSubscriptionsRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.SUBSCRIPTION_TRANSFER_SUBSCRIPTIONS, + (context, request) -> + serviceSet.onTransferSubscriptions(context, (TransferSubscriptionsRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.SUBSCRIPTION_SET_PUBLISHING_MODE, + (context, request) -> + serviceSet.onSetPublishingMode(context, (SetPublishingModeRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.SUBSCRIPTION_PUBLISH, + (context, request) -> + serviceSet.onPublish(context, (PublishRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.SUBSCRIPTION_REPUBLISH, + (context, request) -> + serviceSet.onRepublish(context, (RepublishRequest) request) + .thenApply(Function.identity()) + ); + } + + public void addServiceSet(String path, ViewServiceSet serviceSet) { + serviceHandlerTable.put( + path, + Service.VIEW_BROWSE, + (context, request) -> + serviceSet.onBrowse(context, (BrowseRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.VIEW_BROWSE_NEXT, + (context, request) -> + serviceSet.onBrowseNext(context, (BrowseNextRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.VIEW_TRANSLATE_BROWSE_PATHS, + (context, request) -> + serviceSet.onTranslateBrowsePaths(context, (TranslateBrowsePathsToNodeIdsRequest) request) + .thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.VIEW_REGISTER_NODES, + (context, request) -> + serviceSet.onRegisterNodes(context, (RegisterNodesRequest) request).thenApply(Function.identity()) + ); + serviceHandlerTable.put( + path, + Service.VIEW_UNREGISTER_NODES, + (context, request) -> + serviceSet.onUnregisterNodes(context, (UnregisterNodesRequest) request).thenApply(Function.identity()) + ); + } + + protected void addServiceHandler(String path, Service service, ServiceHandler serviceHandler) { + serviceHandlerTable.put(path, service, serviceHandler); + } + + protected @Nullable ServiceHandler getServiceHandler(String path, Service service) { + return serviceHandlerTable.get(path, service); + } + + protected interface ServiceHandler { + CompletableFuture handle( + ServiceRequestContext context, + UaRequestMessageType requestMessage + ); + } + + private static class ServiceHandlerTable { + + private final ConcurrentMap> table = new ConcurrentHashMap<>(); + + public @Nullable ServiceHandler get(String path, Service service) { + ConcurrentMap handlers = table.get(path); + if (handlers != null) { + return handlers.get(service); + } else { + return null; + } + } + + public void put(String path, Service service, ServiceHandler handler) { + ConcurrentMap handlers = table.computeIfAbsent( + path, + k -> new ConcurrentHashMap<>() + ); + + handlers.put(service, handler); + } + + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/OpcUaServer.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/OpcUaServer.java index 72dd9b379..89430ea43 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/OpcUaServer.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/OpcUaServer.java @@ -10,10 +10,13 @@ package org.eclipse.milo.opcua.sdk.server; +import java.net.InetSocketAddress; import java.security.KeyPair; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Optional; @@ -23,6 +26,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; import java.util.stream.Stream; import com.google.common.collect.Sets; @@ -30,6 +34,7 @@ import org.eclipse.milo.opcua.sdk.server.api.AddressSpaceManager; import org.eclipse.milo.opcua.sdk.server.api.EventListener; import org.eclipse.milo.opcua.sdk.server.api.EventNotifier; +import org.eclipse.milo.opcua.sdk.server.api.config.EndpointConfig; import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig; import org.eclipse.milo.opcua.sdk.server.diagnostics.ServerDiagnosticsSummary; import org.eclipse.milo.opcua.sdk.server.model.ObjectTypeInitializer; @@ -38,34 +43,60 @@ import org.eclipse.milo.opcua.sdk.server.namespaces.OpcUaNamespace; import org.eclipse.milo.opcua.sdk.server.namespaces.ServerNamespace; import org.eclipse.milo.opcua.sdk.server.nodes.factories.EventFactory; +import org.eclipse.milo.opcua.sdk.server.services.Service; +import org.eclipse.milo.opcua.sdk.server.services.impl.DefaultAttributeServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.impl.DefaultDiscoveryServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.impl.DefaultMethodServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.impl.DefaultMonitoredItemServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.impl.DefaultNodeManagementServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.impl.DefaultSessionServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.impl.DefaultSubscriptionServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.impl.DefaultViewServiceSet; import org.eclipse.milo.opcua.sdk.server.subscriptions.Subscription; import org.eclipse.milo.opcua.stack.core.BuiltinReferenceType; import org.eclipse.milo.opcua.stack.core.NamespaceTable; import org.eclipse.milo.opcua.stack.core.ReferenceType; import org.eclipse.milo.opcua.stack.core.ServerTable; import org.eclipse.milo.opcua.stack.core.Stack; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; +import org.eclipse.milo.opcua.stack.core.channel.messages.ErrorMessage; +import org.eclipse.milo.opcua.stack.core.encoding.DefaultEncodingManager; import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; import org.eclipse.milo.opcua.stack.core.encoding.EncodingManager; +import org.eclipse.milo.opcua.stack.core.security.CertificateManager; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; import org.eclipse.milo.opcua.stack.core.types.DataTypeManager; +import org.eclipse.milo.opcua.stack.core.types.DefaultDataTypeManager; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; +import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; +import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; +import org.eclipse.milo.opcua.stack.core.util.Lazy; import org.eclipse.milo.opcua.stack.core.util.ManifestUtil; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.eclipse.milo.opcua.stack.server.services.AttributeHistoryServiceSet; -import org.eclipse.milo.opcua.stack.server.services.AttributeServiceSet; -import org.eclipse.milo.opcua.stack.server.services.MethodServiceSet; -import org.eclipse.milo.opcua.stack.server.services.MonitoredItemServiceSet; -import org.eclipse.milo.opcua.stack.server.services.NodeManagementServiceSet; -import org.eclipse.milo.opcua.stack.server.services.SessionServiceSet; -import org.eclipse.milo.opcua.stack.server.services.SubscriptionServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ViewServiceSet; +import org.eclipse.milo.opcua.stack.transport.server.OpcServerTransport; +import org.eclipse.milo.opcua.stack.transport.server.OpcServerTransportFactory; +import org.eclipse.milo.opcua.stack.transport.server.ServerApplicationContext; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OpcUaServer { +import static java.util.stream.Collectors.toList; +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ubyte; +import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; + +public class OpcUaServer extends AbstractServiceHandler { public static final String SDK_VERSION = ManifestUtil.read("X-SDK-Version").orElse("dev"); @@ -79,56 +110,107 @@ public class OpcUaServer { private final Logger logger = LoggerFactory.getLogger(getClass()); - private final Map referenceTypes = new ConcurrentHashMap<>(); + private final Lazy applicationDescription = new Lazy<>(); private final Map subscriptions = new ConcurrentHashMap<>(); - private final AtomicLong monitoredItemCount = new AtomicLong(0L); + private final NamespaceTable namespaceTable = new NamespaceTable(); + private final ServerTable serverTable = new ServerTable(); + private final AddressSpaceManager addressSpaceManager = new AddressSpaceManager(this); private final SessionManager sessionManager = new SessionManager(this); + + private final EncodingManager encodingManager = + DefaultEncodingManager.createAndInitialize(); + private final ObjectTypeManager objectTypeManager = new ObjectTypeManager(); private final VariableTypeManager variableTypeManager = new VariableTypeManager(); + private final DataTypeManager dataTypeManager = + DefaultDataTypeManager.createAndInitialize(namespaceTable); + private final Map referenceTypes = new ConcurrentHashMap<>(); + private final Set registeredViews = Sets.newConcurrentHashSet(); private final ServerDiagnosticsSummary diagnosticsSummary = new ServerDiagnosticsSummary(this); + private final AtomicLong secureChannelIds = new AtomicLong(); + private final AtomicLong secureChannelTokenIds = new AtomicLong(); + + private final Map transports = new ConcurrentHashMap<>(); + private final EventBus eventBus = new EventBus("server"); private final EventFactory eventFactory = new EventFactory(this); private final EventNotifier eventNotifier = new ServerEventNotifier(); - private final UaStackServer stackServer; + private final EncodingContext encodingContext; private final OpcUaNamespace opcUaNamespace; private final ServerNamespace serverNamespace; + private final OpcUaServerConfig config; + private final OpcServerTransportFactory transportFactory; + private final ServerApplicationContext applicationContext; - public OpcUaServer(OpcUaServerConfig config) { + public OpcUaServer(OpcUaServerConfig config, OpcServerTransportFactory transportFactory) { this.config = config; + this.transportFactory = transportFactory; - stackServer = new UaStackServer(config); + applicationContext = new ServerApplicationContextImpl(); - Stream paths = stackServer.getConfig().getEndpoints() + encodingContext = new EncodingContext() { + @Override + public DataTypeManager getDataTypeManager() { + return dataTypeManager; + } + + @Override + public EncodingManager getEncodingManager() { + return encodingManager; + } + + @Override + public EncodingLimits getEncodingLimits() { + return config.getEncodingLimits(); + } + + @Override + public NamespaceTable getNamespaceTable() { + return namespaceTable; + } + + @Override + public ServerTable getServerTable() { + return serverTable; + } + }; + + Stream paths = config.getEndpoints() .stream() .map(e -> EndpointUtil.getPath(e.getEndpointUrl())) .distinct(); - paths.filter(path -> !path.endsWith("/discovery")).forEach(path -> { - stackServer.addServiceSet(path, (AttributeServiceSet) sessionManager); - stackServer.addServiceSet(path, (AttributeHistoryServiceSet) sessionManager); - stackServer.addServiceSet(path, (MethodServiceSet) sessionManager); - stackServer.addServiceSet(path, (MonitoredItemServiceSet) sessionManager); - stackServer.addServiceSet(path, (NodeManagementServiceSet) sessionManager); - stackServer.addServiceSet(path, (SessionServiceSet) sessionManager); - stackServer.addServiceSet(path, (SubscriptionServiceSet) sessionManager); - stackServer.addServiceSet(path, (ViewServiceSet) sessionManager); + paths.forEach(path -> { + addServiceSet(path, new DefaultDiscoveryServiceSet(OpcUaServer.this)); + + if (!path.endsWith("/discovery")) { + addServiceSet(path, new DefaultAttributeServiceSet(OpcUaServer.this)); + addServiceSet(path, new DefaultMethodServiceSet(OpcUaServer.this)); + addServiceSet(path, new DefaultMonitoredItemServiceSet(OpcUaServer.this)); + addServiceSet(path, new DefaultNodeManagementServiceSet(OpcUaServer.this)); + addServiceSet(path, new DefaultSessionServiceSet(OpcUaServer.this)); + addServiceSet(path, new DefaultSubscriptionServiceSet(OpcUaServer.this)); + addServiceSet(path, new DefaultViewServiceSet(OpcUaServer.this)); + } }); - ObjectTypeInitializer.initialize(stackServer.getNamespaceTable(), objectTypeManager); + ObjectTypeInitializer.initialize(namespaceTable, objectTypeManager); - VariableTypeInitializer.initialize(stackServer.getNamespaceTable(), variableTypeManager); + VariableTypeInitializer.initialize(namespaceTable, variableTypeManager); + + serverTable.add(config.getApplicationUri()); opcUaNamespace = new OpcUaNamespace(this); opcUaNamespace.startup(); @@ -141,15 +223,44 @@ public OpcUaServer(OpcUaServerConfig config) { } } - public OpcUaServerConfig getConfig() { - return config; - } - public CompletableFuture startup() { eventFactory.startup(); - return stackServer.startup() - .thenApply(s -> OpcUaServer.this); + config.getEndpoints() + .stream() + .sorted(Comparator.comparing(EndpointConfig::getTransportProfile)) + .forEach(endpoint -> { + logger.info( + "Binding endpoint {} to {}:{} [{}/{}]", + endpoint.getEndpointUrl(), + endpoint.getBindAddress(), + endpoint.getBindPort(), + endpoint.getSecurityPolicy(), + endpoint.getSecurityMode() + ); + + TransportProfile transportProfile = endpoint.getTransportProfile(); + + OpcServerTransport transport = transports.computeIfAbsent( + transportProfile, + transportFactory::create + ); + + if (transport != null) { + try { + var bindAddress = new InetSocketAddress(endpoint.getBindAddress(), endpoint.getBindPort()); + transport.bind(applicationContext, bindAddress); + + transports.put(transportProfile, transport); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + logger.warn("No OpcServerTransport for TransportProfile: {}", transportProfile); + } + }); + + return CompletableFuture.completedFuture(this); } public CompletableFuture shutdown() { @@ -161,12 +272,24 @@ public CompletableFuture shutdown() { subscriptions.values() .forEach(Subscription::deleteSubscription); - return stackServer.shutdown() - .thenApply(s -> OpcUaServer.this); + transports.values().forEach(transport -> { + try { + transport.unbind(); + } catch (Exception e) { + logger.warn("Error unbinding transport", e); + } + }); + transports.clear(); + + return CompletableFuture.completedFuture(this); } - public UaStackServer getStackServer() { - return stackServer; + public OpcUaServerConfig getConfig() { + return config; + } + + public ServerApplicationContext getApplicationContext() { + return applicationContext; } public AddressSpaceManager getAddressSpaceManager() { @@ -186,23 +309,23 @@ public ServerNamespace getServerNamespace() { } public DataTypeManager getDataTypeManager() { - return stackServer.getDataTypeManager(); + return dataTypeManager; } public EncodingManager getEncodingManager() { - return stackServer.getEncodingManager(); + return encodingManager; } public NamespaceTable getNamespaceTable() { - return stackServer.getNamespaceTable(); + return namespaceTable; } public ServerTable getServerTable() { - return stackServer.getServerTable(); + return serverTable; } public EncodingContext getEncodingContext() { - return stackServer.getEncodingContext(); + return encodingContext; } public ServerDiagnosticsSummary getDiagnosticsSummary() { @@ -261,33 +384,234 @@ public AtomicLong getMonitoredItemCount() { } public Optional getKeyPair(ByteString thumbprint) { - return stackServer.getConfig().getCertificateManager().getKeyPair(thumbprint); + return config.getCertificateManager().getKeyPair(thumbprint); } public Optional getCertificate(ByteString thumbprint) { - return stackServer.getConfig().getCertificateManager().getCertificate(thumbprint); + return config.getCertificateManager().getCertificate(thumbprint); } public Optional getCertificateChain(ByteString thumbprint) { - return stackServer.getConfig().getCertificateManager().getCertificateChain(thumbprint); + return config.getCertificateManager().getCertificateChain(thumbprint); } public ExecutorService getExecutorService() { - return stackServer.getConfig().getExecutor(); + return config.getExecutor(); } public ScheduledExecutorService getScheduledExecutorService() { return config.getScheduledExecutorService(); } - public List getEndpointDescriptions() { - return stackServer.getEndpointDescriptions(); - } - public Map getReferenceTypes() { return referenceTypes; } + + private class ServerApplicationContextImpl implements ServerApplicationContext { + + @Override + public List getEndpointDescriptions() { + return config.getEndpoints() + .stream() + .map(this::transformEndpoint) + .collect(Collectors.toUnmodifiableList()); + } + + @Override + public EncodingContext getEncodingContext() { + return encodingContext; + } + + @Override + public CertificateManager getCertificateManager() { + return config.getCertificateManager(); + } + + @Override + public CertificateValidator getCertificateValidator() { + return config.getCertificateValidator(); + } + + @Override + public Long getNextSecureChannelId() { + return secureChannelIds.getAndIncrement(); + } + + @Override + public Long getNextSecureChannelTokenId() { + return secureChannelTokenIds.getAndIncrement(); + } + + @Override + public CompletableFuture handleServiceRequest( + ServiceRequestContext context, + UaRequestMessageType requestMessage + ) { + + String path = EndpointUtil.getPath(context.getEndpointUrl()); + + if (context.getSecureChannel().getSecurityPolicy() == SecurityPolicy.None) { + if (getEndpointDescriptions().stream() + .filter(e -> EndpointUtil.getPath(e.getEndpointUrl()).equals(path)) + .filter(e -> e.getTransportProfileUri().equals(context.getTransportProfile().getUri())) + .noneMatch(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri())) + ) { + + if (!isDiscoveryService(requestMessage)) { + var errorMessage = new ErrorMessage( + StatusCodes.Bad_SecurityPolicyRejected, + StatusCodes.lookup(StatusCodes.Bad_SecurityPolicyRejected) + .map(ss -> ss[1]).orElse("") + ); + + context.getChannel().pipeline().fireUserEventTriggered(errorMessage); + + // won't complete, doesn't matter, we're closing down + return new CompletableFuture<>(); + } + } + } + + Service service = Service.from(requestMessage.getTypeId()); + + ServiceHandler serviceHandler = service != null ? getServiceHandler(path, service) : null; + + if (serviceHandler != null) { + return serviceHandler.handle(context, requestMessage); + } else { + logger.warn("No ServiceHandler registered for path={} service={}", path, service); + + return CompletableFuture.failedFuture(new UaException(StatusCodes.Bad_NotImplemented)); + } + } + + /** + * Return {@code true} if {@code requestMessage} is one of the Discovery service requests: + *

    + *
  • FindServersRequest
  • + *
  • GetEndpointsRequest
  • + *
  • RegisterServerRequest
  • + *
  • FindServersOnNetworkRequest
  • + *
  • RegisterServer2Request
  • + *
+ * + * @param requestMessage the {@link UaRequestMessageType} to check. + * @return {@code true} if {@code requestMessage} is one of the Discovery service requests. + */ + private boolean isDiscoveryService(UaRequestMessageType requestMessage) { + Service service = Service.from(requestMessage.getTypeId()); + + if (service != null) { + switch (service) { + case DISCOVERY_FIND_SERVERS: + case DISCOVERY_GET_ENDPOINTS: + case DISCOVERY_REGISTER_SERVER: + case DISCOVERY_FIND_SERVERS_ON_NETWORK: + case DISCOVERY_REGISTER_SERVER_2: + return true; + + default: + return false; + } + } + + return false; + } + + private EndpointDescription transformEndpoint(EndpointConfig endpoint) { + return new EndpointDescription( + endpoint.getEndpointUrl(), + getApplicationDescription(), + certificateByteString(endpoint.getCertificate()), + endpoint.getSecurityMode(), + endpoint.getSecurityPolicy().getUri(), + a(endpoint.getTokenPolicies(), UserTokenPolicy.class), + endpoint.getTransportProfile().getUri(), + ubyte(getSecurityLevel(endpoint.getSecurityPolicy(), endpoint.getSecurityMode())) + ); + } + + private ByteString certificateByteString(@Nullable X509Certificate certificate) { + if (certificate != null) { + try { + return ByteString.of(certificate.getEncoded()); + } catch (CertificateEncodingException e) { + logger.error("Error decoding certificate.", e); + return ByteString.NULL_VALUE; + } + } else { + return ByteString.NULL_VALUE; + } + } + + + private ApplicationDescription getApplicationDescription() { + return applicationDescription.getOrCompute(() -> { + List discoveryUrls = config.getEndpoints() + .stream() + .map(EndpointConfig::getEndpointUrl) + .filter(url -> url.endsWith("/discovery")) + .distinct() + .collect(toList()); + + if (discoveryUrls.isEmpty()) { + discoveryUrls = config.getEndpoints() + .stream() + .map(EndpointConfig::getEndpointUrl) + .distinct() + .collect(toList()); + } + + return new ApplicationDescription( + config.getApplicationUri(), + config.getProductUri(), + config.getApplicationName(), + ApplicationType.Server, + null, + null, + a(discoveryUrls, String.class) + ); + }); + } + + private short getSecurityLevel(SecurityPolicy securityPolicy, MessageSecurityMode securityMode) { + short securityLevel = 0; + + switch (securityPolicy) { + case Aes256_Sha256_RsaPss: + case Basic256Sha256: + securityLevel |= 0x08; + break; + case Aes128_Sha256_RsaOaep: + securityLevel |= 0x04; + break; + case Basic256: + case Basic128Rsa15: + securityLevel |= 0x01; + break; + case None: + default: + break; + } + + switch (securityMode) { + case SignAndEncrypt: + securityLevel |= 0x80; + break; + case Sign: + securityLevel |= 0x40; + break; + default: + securityLevel |= 0x20; + break; + } + + return securityLevel; + } + + } + private static class ServerEventNotifier implements EventNotifier { private final List eventListeners = Collections.synchronizedList(new ArrayList<>()); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/Session.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/Session.java index 66acb74a8..98aac1290 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/Session.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/Session.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -24,17 +24,8 @@ import org.eclipse.milo.opcua.sdk.server.diagnostics.SessionDiagnostics; import org.eclipse.milo.opcua.sdk.server.diagnostics.SessionSecurityDiagnostics; -import org.eclipse.milo.opcua.sdk.server.services.DefaultAttributeHistoryServiceSet; -import org.eclipse.milo.opcua.sdk.server.services.DefaultAttributeServiceSet; -import org.eclipse.milo.opcua.sdk.server.services.DefaultMethodServiceSet; -import org.eclipse.milo.opcua.sdk.server.services.DefaultMonitoredItemServiceSet; -import org.eclipse.milo.opcua.sdk.server.services.DefaultNodeManagementServiceSet; -import org.eclipse.milo.opcua.sdk.server.services.DefaultQueryServiceSet; -import org.eclipse.milo.opcua.sdk.server.services.DefaultSubscriptionServiceSet; -import org.eclipse.milo.opcua.sdk.server.services.DefaultViewServiceSet; -import org.eclipse.milo.opcua.sdk.server.services.helpers.BrowseHelper.BrowseContinuationPoint; +import org.eclipse.milo.opcua.sdk.server.services.impl.helpers.BrowseHelper.BrowseContinuationPoint; import org.eclipse.milo.opcua.sdk.server.subscriptions.SubscriptionManager; -import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; @@ -42,23 +33,17 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; import org.eclipse.milo.opcua.stack.core.types.structured.AnonymousIdentityToken; import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.CancelResponse; import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; import org.eclipse.milo.opcua.stack.core.types.structured.IssuedIdentityToken; import org.eclipse.milo.opcua.stack.core.types.structured.UserIdentityToken; import org.eclipse.milo.opcua.stack.core.types.structured.UserNameIdentityToken; import org.eclipse.milo.opcua.stack.core.types.structured.X509IdentityToken; import org.eclipse.milo.opcua.stack.core.util.CertificateUtil; -import org.eclipse.milo.opcua.stack.server.services.NodeManagementServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; -import org.eclipse.milo.opcua.stack.server.services.SessionServiceSet; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - -public class Session implements SessionServiceSet { +public class Session { private static final int IDENTITY_HISTORY_MAX_SIZE = 10; @@ -80,15 +65,6 @@ public class Session implements SessionServiceSet { private volatile long lastActivityNanos = System.nanoTime(); private volatile ScheduledFuture checkTimeoutFuture; - private final DefaultAttributeServiceSet attributeServiceSet; - private final DefaultAttributeHistoryServiceSet attributeHistoryServiceSet; - private final DefaultMethodServiceSet methodServiceSet; - private final DefaultMonitoredItemServiceSet monitoredItemServiceSet; - private final DefaultNodeManagementServiceSet nodeManagementServiceSet; - private final DefaultQueryServiceSet queryServiceSet; - private final DefaultSubscriptionServiceSet subscriptionServiceSet; - private final DefaultViewServiceSet viewServiceSet; - private volatile EndpointDescription endpoint; private volatile long secureChannelId; private volatile SecurityConfiguration securityConfiguration; @@ -137,15 +113,6 @@ public Session( subscriptionManager = new SubscriptionManager(this, server); - attributeServiceSet = new DefaultAttributeServiceSet(); - attributeHistoryServiceSet = new DefaultAttributeHistoryServiceSet(); - methodServiceSet = new DefaultMethodServiceSet(); - monitoredItemServiceSet = new DefaultMonitoredItemServiceSet(subscriptionManager); - nodeManagementServiceSet = new DefaultNodeManagementServiceSet(); - queryServiceSet = new DefaultQueryServiceSet(); - subscriptionServiceSet = new DefaultSubscriptionServiceSet(subscriptionManager); - viewServiceSet = new DefaultViewServiceSet(server.getConfig().getExecutor()); - checkTimeoutFuture = server.getScheduledExecutorService().schedule( this::checkTimeout, sessionTimeout.toNanos(), TimeUnit.NANOSECONDS); } @@ -344,57 +311,9 @@ public void setLocaleIds(@Nullable String[] localeIds) { this.localeIds = localeIds; } - public DefaultAttributeServiceSet getAttributeServiceSet() { - return attributeServiceSet; - } - - public DefaultAttributeHistoryServiceSet getAttributeHistoryServiceSet() { - return attributeHistoryServiceSet; - } - - public DefaultMethodServiceSet getMethodServiceSet() { - return methodServiceSet; - } - - public DefaultMonitoredItemServiceSet getMonitoredItemServiceSet() { - return monitoredItemServiceSet; - } - - public NodeManagementServiceSet getNodeManagementServiceSet() { - return nodeManagementServiceSet; - } - - public DefaultQueryServiceSet getQueryServiceSet() { - return queryServiceSet; - } - - public DefaultSubscriptionServiceSet getSubscriptionServiceSet() { - return subscriptionServiceSet; - } - - public DefaultViewServiceSet getViewServiceSet() { - return viewServiceSet; - } - public SubscriptionManager getSubscriptionManager() { return subscriptionManager; } - //region Session Services - - @Override - public void onCreateSession(ServiceRequest serviceRequest) { - serviceRequest.setServiceFault(StatusCodes.Bad_InternalError); - } - - @Override - public void onActivateSession(ServiceRequest serviceRequest) { - serviceRequest.setServiceFault(StatusCodes.Bad_InternalError); - } - - @Override - public void onCloseSession(ServiceRequest serviceRequest) { - serviceRequest.setServiceFault(StatusCodes.Bad_InternalError); - } void close(boolean deleteSubscriptions) { if (checkTimeoutFuture != null) { @@ -406,12 +325,6 @@ void close(boolean deleteSubscriptions) { listeners.forEach(listener -> listener.onSessionClosed(this, deleteSubscriptions)); } - @Override - public void onCancel(ServiceRequest serviceRequest) { - serviceRequest.setResponse(new CancelResponse(serviceRequest.createResponseHeader(), uint(0))); - } - //endregion - @Nullable private static String getClientUserId(UserIdentityToken identityToken) { UserTokenType tokenType = getTokenType(identityToken); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/SessionManager.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/SessionManager.java index 417b1619e..cc9a6664e 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/SessionManager.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/SessionManager.java @@ -23,16 +23,16 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Stream; import com.google.common.base.Objects; import com.google.common.math.DoubleMath; import com.google.common.primitives.Bytes; -import org.eclipse.milo.opcua.sdk.server.diagnostics.ServerDiagnosticsSummary; import org.eclipse.milo.opcua.sdk.server.identity.IdentityValidator; -import org.eclipse.milo.opcua.sdk.server.services.ServiceAttributes; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.UaRuntimeException; +import org.eclipse.milo.opcua.stack.core.channel.SecureChannel; import org.eclipse.milo.opcua.stack.core.security.SecurityAlgorithm; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; @@ -53,45 +53,27 @@ import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionRequest; import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionResponse; import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; import org.eclipse.milo.opcua.stack.core.types.structured.SignatureData; import org.eclipse.milo.opcua.stack.core.types.structured.SignedSoftwareCertificate; import org.eclipse.milo.opcua.stack.core.types.structured.UserIdentityToken; import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; -import org.eclipse.milo.opcua.stack.core.util.CertificateUtil; import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; import org.eclipse.milo.opcua.stack.core.util.NonceUtil; import org.eclipse.milo.opcua.stack.core.util.SignatureUtil; -import org.eclipse.milo.opcua.stack.server.security.ServerCertificateValidator; -import org.eclipse.milo.opcua.stack.server.services.AttributeHistoryServiceSet; -import org.eclipse.milo.opcua.stack.server.services.AttributeServiceSet; -import org.eclipse.milo.opcua.stack.server.services.MethodServiceSet; -import org.eclipse.milo.opcua.stack.server.services.MonitoredItemServiceSet; -import org.eclipse.milo.opcua.stack.server.services.NodeManagementServiceSet; -import org.eclipse.milo.opcua.stack.server.services.QueryServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; -import org.eclipse.milo.opcua.stack.server.services.SessionServiceSet; -import org.eclipse.milo.opcua.stack.server.services.SubscriptionServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ViewServiceSet; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static java.util.Objects.requireNonNullElse; +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; import static org.eclipse.milo.opcua.stack.core.util.DigestUtil.sha1; -public class SessionManager implements - AttributeServiceSet, - AttributeHistoryServiceSet, - MethodServiceSet, - MonitoredItemServiceSet, - NodeManagementServiceSet, - QueryServiceSet, - SessionServiceSet, - SubscriptionServiceSet, - ViewServiceSet { +public class SessionManager { private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -165,9 +147,9 @@ public UInteger getCurrentSessionCount() { return uint(createdSessions.size() + activeSessions.size()); } - private Session session(ServiceRequest service) throws UaException { - long secureChannelId = service.getSecureChannelId(); - NodeId authToken = service.getRequest().getRequestHeader().getAuthenticationToken(); + public Session getSession(ServiceRequestContext context, RequestHeader requestHeader) throws UaException { + long secureChannelId = context.getSecureChannel().getChannelId(); + NodeId authToken = requestHeader.getAuthenticationToken(); Session session = activeSessions.get(authToken); @@ -191,37 +173,14 @@ private Session session(ServiceRequest service) throws UaException { session.updateLastActivity(); - service.attr(ServiceAttributes.SERVER_KEY).set(server); - service.attr(ServiceAttributes.SESSION_KEY).set(session); - return session; } } - //region Session Services - @Override - public void onCreateSession(ServiceRequest serviceRequest) { - ServerDiagnosticsSummary serverDiagnosticsSummary = server.getDiagnosticsSummary(); - - try { - CreateSessionResponse response = createSession(serviceRequest); - - serverDiagnosticsSummary.getCumulatedSessionCount().increment(); - - serviceRequest.setResponse(response); - } catch (UaException e) { - serverDiagnosticsSummary.getRejectedSessionCount().increment(); - - if (e.getStatusCode().isSecurityError()) { - serverDiagnosticsSummary.getSecurityRejectedSessionCount().increment(); - } - - serviceRequest.setServiceFault(e); - } - } - - private CreateSessionResponse createSession(ServiceRequest serviceRequest) throws UaException { - CreateSessionRequest request = (CreateSessionRequest) serviceRequest.getRequest(); + public CreateSessionResponse createSession( + ServiceRequestContext context, + CreateSessionRequest request + ) throws UaException { long maxSessionCount = server.getConfig().getLimits().getMaxSessionCount().longValue(); if (createdSessions.size() + activeSessions.size() >= maxSessionCount) { @@ -230,7 +189,7 @@ private CreateSessionResponse createSession(ServiceRequest serviceRequest) throw ByteString serverNonce = NonceUtil.generateNonce(32); NodeId authenticationToken = new NodeId(0, NonceUtil.generateNonce(32)); - long maxRequestMessageSize = serviceRequest.getServer().getConfig().getEncodingLimits().getMaxMessageSize(); + long maxRequestMessageSize = server.getConfig().getEncodingLimits().getMaxMessageSize(); double revisedSessionTimeout = Math.max( 5000, Math.min(server.getConfig().getLimits().getMaxSessionTimeout(), request.getRequestedSessionTimeout()) @@ -238,16 +197,16 @@ private CreateSessionResponse createSession(ServiceRequest serviceRequest) throw ApplicationDescription clientDescription = request.getClientDescription(); - long secureChannelId = serviceRequest.getSecureChannelId(); - EndpointDescription endpoint = serviceRequest.getEndpoint(); - - SecurityPolicy securityPolicy = SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()); + long secureChannelId = context.getSecureChannel().getChannelId(); + SecurityPolicy securityPolicy = context.getSecureChannel().getSecurityPolicy(); + String transportProfileUri = context.getTransportProfile().getUri(); - EndpointDescription[] serverEndpoints = server.getEndpointDescriptions() + EndpointDescription[] serverEndpoints = server.getApplicationContext() + .getEndpointDescriptions() .stream() .filter(ed -> !ed.getEndpointUrl().endsWith("/discovery")) .filter(ed -> endpointMatchesUrl(ed, request.getEndpointUrl())) - .filter(ed -> Objects.equal(endpoint.getTransportProfileUri(), ed.getTransportProfileUri())) + .filter(ed -> Objects.equal(transportProfileUri, ed.getTransportProfileUri())) .map(SessionManager::stripNonEssentialFields) .toArray(EndpointDescription[]::new); @@ -255,10 +214,11 @@ private CreateSessionResponse createSession(ServiceRequest serviceRequest) throw // GetEndpoints in UaStackServer returns *all* endpoints regardless of a hostname // match in the endpoint URL if the result after filtering is 0 endpoints. Do the // same here. - serverEndpoints = server.getEndpointDescriptions() + serverEndpoints = server.getApplicationContext() + .getEndpointDescriptions() .stream() .filter(ed -> !ed.getEndpointUrl().endsWith("/discovery")) - .filter(ed -> Objects.equal(endpoint.getTransportProfileUri(), ed.getTransportProfileUri())) + .filter(ed -> Objects.equal(transportProfileUri, ed.getTransportProfileUri())) .map(SessionManager::stripNonEssentialFields) .toArray(EndpointDescription[]::new); } @@ -280,24 +240,24 @@ private CreateSessionResponse createSession(ServiceRequest serviceRequest) throw } } - ByteString clientCertificateBytes = request.getClientCertificate(); + ByteString clientCertificateBytesFromRequest = + request.getClientCertificate(); - if (securityPolicy != SecurityPolicy.None && - serviceRequest.getClientCertificateBytes() != null) { + ByteString clientCertificateBytesFromSecureChannel = + context.getSecureChannel().getRemoteCertificateBytes(); - if (!Objects.equal(clientCertificateBytes, - serviceRequest.getClientCertificateBytes())) { - - throw new UaException(StatusCodes.Bad_SecurityChecksFailed, + if (securityPolicy != SecurityPolicy.None) { + if (!Objects.equal(clientCertificateBytesFromRequest, clientCertificateBytesFromSecureChannel)) { + throw new UaException( + StatusCodes.Bad_SecurityChecksFailed, "certificate used to open secure channel " + - "differs from certificate used to create session"); + "differs from certificate used to create session" + ); } } - SecurityConfiguration securityConfiguration = createSecurityConfiguration( - endpoint, - clientCertificateBytes - ); + SecurityConfiguration securityConfiguration = + createSecurityConfiguration(context.getSecureChannel()); if (securityPolicy != SecurityPolicy.None) { X509Certificate clientCertificate = @@ -309,13 +269,11 @@ private CreateSessionResponse createSession(ServiceRequest serviceRequest) throw if (clientCertificate == null || clientCertificateChain == null) { throw new UaException( StatusCodes.Bad_SecurityChecksFailed, - "client certificate must be non-null"); + "client certificate must be non-null" + ); } - ServerCertificateValidator certificateValidator = - server.getConfig().getCertificateValidator(); - - certificateValidator.validateCertificateChain( + server.getConfig().getCertificateValidator().validateCertificateChain( clientCertificateChain, clientDescription.getApplicationUri() ); @@ -342,7 +300,7 @@ private CreateSessionResponse createSession(ServiceRequest serviceRequest) throw clientDescription, request.getServerUri(), request.getMaxResponseMessageSize(), - endpoint, + findSessionEndpoint(context), secureChannelId, securityConfiguration ); @@ -361,12 +319,12 @@ private CreateSessionResponse createSession(ServiceRequest serviceRequest) throw sessionListeners.forEach(l -> l.onSessionCreated(session)); return new CreateSessionResponse( - serviceRequest.createResponseHeader(), + createResponseHeader(request), sessionId, authenticationToken, revisedSessionTimeout, serverNonce, - endpoint.getServerCertificate(), + securityConfiguration.getServerCertificateBytes(), serverEndpoints, new SignedSoftwareCertificate[0], serverSignature, @@ -374,12 +332,9 @@ private CreateSessionResponse createSession(ServiceRequest serviceRequest) throw ); } - private SecurityConfiguration createSecurityConfiguration( - EndpointDescription endpoint, - ByteString clientCertificateBytes) throws UaException { - - SecurityPolicy securityPolicy = SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()); - MessageSecurityMode securityMode = endpoint.getSecurityMode(); + private SecurityConfiguration createSecurityConfiguration(SecureChannel secureChannel) throws UaException { + SecurityPolicy securityPolicy = secureChannel.getSecurityPolicy(); + MessageSecurityMode securityMode = secureChannel.getMessageSecurityMode(); X509Certificate clientCertificate = null; List clientCertificateChain = null; @@ -389,28 +344,22 @@ private SecurityConfiguration createSecurityConfiguration( List serverCertificateChain = null; if (securityPolicy != SecurityPolicy.None) { - clientCertificate = CertificateUtil - .decodeCertificate(clientCertificateBytes.bytes()); - - clientCertificateChain = CertificateUtil - .decodeCertificates(clientCertificateBytes.bytes()); + clientCertificate = secureChannel.getRemoteCertificate(); + clientCertificateChain = secureChannel.getRemoteCertificateChain(); - ByteString thumbprint = ByteString.of(sha1(endpoint.getServerCertificate().bytesOrEmpty())); + ByteString thumbprint = ByteString.of(sha1(secureChannel.getLocalCertificateBytes().bytes())); - keyPair = server - .getConfig() + keyPair = server.getConfig() .getCertificateManager() .getKeyPair(thumbprint) .orElseThrow(() -> new UaException(StatusCodes.Bad_ConfigurationError)); - serverCertificate = server - .getConfig() + serverCertificate = server.getConfig() .getCertificateManager() .getCertificate(thumbprint) .orElseThrow(() -> new UaException(StatusCodes.Bad_ConfigurationError)); - serverCertificateChain = server - .getConfig() + serverCertificateChain = server.getConfig() .getCertificateManager() .getCertificateChain(thumbprint) .map(List::of) @@ -477,29 +426,8 @@ private static EndpointDescription stripNonEssentialFields(EndpointDescription e ); } - @Override - public void onActivateSession(ServiceRequest serviceRequest) { - try { - ActivateSessionResponse response = activateSession(serviceRequest); - - serviceRequest.setResponse(response); - } catch (UaException e) { - ServerDiagnosticsSummary serverDiagnosticsSummary = server.getDiagnosticsSummary(); - - serverDiagnosticsSummary.getRejectedSessionCount().increment(); - - if (e.getStatusCode().isSecurityError()) { - serverDiagnosticsSummary.getSecurityRejectedSessionCount().increment(); - } - - serviceRequest.setServiceFault(e); - } - } - - private ActivateSessionResponse activateSession(ServiceRequest serviceRequest) throws UaException { - ActivateSessionRequest request = (ActivateSessionRequest) serviceRequest.getRequest(); - - long secureChannelId = serviceRequest.getSecureChannelId(); + public ActivateSessionResponse activateSession(ServiceRequestContext context, ActivateSessionRequest request) throws UaException { + long secureChannelId = context.getSecureChannel().getChannelId(); NodeId authToken = request.getRequestHeader().getAuthenticationToken(); List clientSoftwareCertificates = l(request.getClientSoftwareCertificates()); @@ -535,13 +463,13 @@ private ActivateSessionResponse activateSession(ServiceRequest serviceRequest) t ByteString serverNonce = NonceUtil.generateNonce(32); - session.setClientAddress(serviceRequest.getClientAddress()); + session.setClientAddress(context.clientAddress()); session.setIdentityObject(identityObject, identityToken); session.setLastNonce(serverNonce); session.setLocaleIds(request.getLocaleIds()); return new ActivateSessionResponse( - serviceRequest.createResponseHeader(), + createResponseHeader(request), serverNonce, results, new DiagnosticInfo[0] @@ -550,7 +478,7 @@ private ActivateSessionResponse activateSession(ServiceRequest serviceRequest) t /* * Associate session with new secure channel if client certificate and identity token match. */ - ByteString clientCertificateBytes = serviceRequest.getClientCertificateBytes(); + ByteString clientCertificateBytes = context.getSecureChannel().getRemoteCertificateBytes(); UserIdentityToken identityToken = decodeIdentityToken( request.getUserIdentityToken(), @@ -575,11 +503,12 @@ private ActivateSessionResponse activateSession(ServiceRequest serviceRequest) t if (sameIdentity && sameCertificate) { SecurityConfiguration newSecurityConfiguration = createSecurityConfiguration( - serviceRequest.getEndpoint(), - clientCertificateBytes + context.getSecureChannel() ); - session.setEndpoint(serviceRequest.getEndpoint()); + EndpointDescription endpoint = findSessionEndpoint(context); + session.setEndpoint(endpoint); + session.setSecureChannelId(secureChannelId); session.setSecurityConfiguration(newSecurityConfiguration); @@ -591,12 +520,12 @@ private ActivateSessionResponse activateSession(ServiceRequest serviceRequest) t ByteString serverNonce = NonceUtil.generateNonce(32); - session.setClientAddress(serviceRequest.getClientAddress()); + session.setClientAddress(context.clientAddress()); session.setLastNonce(serverNonce); session.setLocaleIds(request.getLocaleIds()); return new ActivateSessionResponse( - serviceRequest.createResponseHeader(), + createResponseHeader(request), serverNonce, results, new DiagnosticInfo[0] @@ -632,13 +561,13 @@ private ActivateSessionResponse activateSession(ServiceRequest serviceRequest) t ByteString serverNonce = NonceUtil.generateNonce(32); - session.setClientAddress(serviceRequest.getClientAddress()); + session.setClientAddress(context.clientAddress()); session.setIdentityObject(identityObject, identityToken); session.setLocaleIds(request.getLocaleIds()); session.setLastNonce(serverNonce); return new ActivateSessionResponse( - serviceRequest.createResponseHeader(), + createResponseHeader(request), serverNonce, results, new DiagnosticInfo[0] @@ -646,6 +575,48 @@ private ActivateSessionResponse activateSession(ServiceRequest serviceRequest) t } } + private EndpointDescription findSessionEndpoint(ServiceRequestContext context) throws UaException { + return server.getApplicationContext() + .getEndpointDescriptions() + .stream() + .filter(e -> { + boolean transportMatch = java.util.Objects.equals( + e.getTransportProfileUri(), + context.getTransportProfile().getUri() + ); + + boolean pathMatch = java.util.Objects.equals( + EndpointUtil.getPath(e.getEndpointUrl()), + EndpointUtil.getPath(context.getEndpointUrl()) + ); + + boolean securityPolicyMatch = java.util.Objects.equals( + e.getSecurityPolicyUri(), + context.getSecureChannel().getSecurityPolicy().getUri() + ); + + boolean securityModeMatch = java.util.Objects.equals( + e.getSecurityMode(), + context.getSecureChannel().getMessageSecurityMode() + ); + + return transportMatch && pathMatch && securityPolicyMatch && securityModeMatch; + }) + .findFirst() + .orElseThrow(() -> { + String message = String.format( + "no matching endpoint found: transportProfile=%s, " + + "endpointUrl=%s, securityPolicy=%s, securityMode=%s", + context.getTransportProfile(), + context.getEndpointUrl(), + context.getSecureChannel().getSecurityPolicy(), + context.getSecureChannel().getMessageSecurityMode() + ); + + return new UaException(StatusCodes.Bad_SecurityChecksFailed, message); + }); + } + private static void verifyClientSignature(Session session, ActivateSessionRequest request) throws UaException { SecurityConfiguration securityConfiguration = session.getSecurityConfiguration(); @@ -723,8 +694,8 @@ private UserIdentityToken decodeIdentityToken( } } - String policyId = l(tokenPolicies).stream() - .filter(p -> p.getTokenType() == UserTokenType.Anonymous) + String policyId = Stream.of(tokenPolicies) + .filter(p -> p != null && p.getTokenType() == UserTokenType.Anonymous) .findFirst() .map(UserTokenPolicy::getPolicyId) .orElse(null); @@ -784,22 +755,13 @@ private UserTokenPolicy validatePolicyId(Session session, Object tokenObject) th } } - @Override - public void onCloseSession(ServiceRequest service) { - try { - CloseSessionResponse response = closeSession(service); + public CloseSessionResponse closeSession( + CloseSessionRequest request, + ServiceRequestContext context + ) throws UaException { - service.setResponse(response); - } catch (UaException e) { - service.setServiceFault(e); - } - } - - private CloseSessionResponse closeSession(ServiceRequest service) throws UaException { - CloseSessionRequest request = (CloseSessionRequest) service.getRequest(); - - long secureChannelId = service.getSecureChannelId(); - NodeId authToken = service.getRequest().getRequestHeader().getAuthenticationToken(); + long secureChannelId = context.getSecureChannel().getChannelId(); + NodeId authToken = request.getRequestHeader().getAuthenticationToken(); Session session = activeSessions.get(authToken); @@ -809,7 +771,7 @@ private CloseSessionResponse closeSession(ServiceRequest service) throws UaExcep } else { activeSessions.remove(authToken); session.close(request.getDeleteSubscriptions()); - return new CloseSessionResponse(service.createResponseHeader()); + return new CloseSessionResponse(createResponseHeader(request)); } } else { session = createdSessions.get(authToken); @@ -821,16 +783,11 @@ private CloseSessionResponse closeSession(ServiceRequest service) throws UaExcep } else { createdSessions.remove(authToken); session.close(request.getDeleteSubscriptions()); - return new CloseSessionResponse(service.createResponseHeader()); + return new CloseSessionResponse(createResponseHeader(request)); } } } - @Override - public void onCancel(ServiceRequest service) throws UaException { - session(service).onCancel(service); - } - private SignatureData getServerSignature( SecurityPolicy securityPolicy, KeyPair keyPair, @@ -857,300 +814,5 @@ private SignatureData getServerSignature( } } } - //endregion - - //region Attribute Services - @Override - public void onRead(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getReadCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getAttributeServiceSet().onRead(service); - } - - @Override - public void onWrite(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getWriteCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getAttributeServiceSet().onWrite(service); - } - - @Override - public void onHistoryRead(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getHistoryReadCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getAttributeHistoryServiceSet().onHistoryRead(service); - } - - @Override - public void onHistoryUpdate(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getHistoryUpdateCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getAttributeHistoryServiceSet().onHistoryUpdate(service); - } - //endregion - - //region View Services - @Override - public void onBrowse(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getBrowseCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getViewServiceSet().onBrowse(service); - } - - @Override - public void onBrowseNext(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getBrowseNextCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getViewServiceSet().onBrowseNext(service); - } - - @Override - public void onTranslateBrowsePaths(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getTranslateBrowsePathsToNodeIdsCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getViewServiceSet().onTranslateBrowsePaths(service); - } - - @Override - public void onRegisterNodes(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getRegisterNodesCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getViewServiceSet().onRegisterNodes(service); - } - - @Override - public void onUnregisterNodes(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getUnregisterNodesCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getViewServiceSet().onUnregisterNodes(service); - } - //endregion - - //region NodeManagement Services - @Override - public void onAddNodes(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getAddNodesCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getNodeManagementServiceSet().onAddNodes(service); - } - - @Override - public void onAddReferences(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getAddReferencesCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getNodeManagementServiceSet().onAddReferences(service); - } - - @Override - public void onDeleteNodes(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getDeleteNodesCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getNodeManagementServiceSet().onDeleteNodes(service); - } - - @Override - public void onDeleteReferences(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getDeleteReferencesCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getNodeManagementServiceSet().onDeleteReferences(service); - } - //endregion - - //region Subscription Services - @Override - public void onCreateSubscription(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getCreateSubscriptionCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getSubscriptionServiceSet().onCreateSubscription(service); - } - - @Override - public void onModifySubscription(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getModifySubscriptionCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getSubscriptionServiceSet().onModifySubscription(service); - } - - @Override - public void onSetPublishingMode(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getSetPublishingModeCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getSubscriptionServiceSet().onSetPublishingMode(service); - } - - @Override - public void onPublish(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getPublishCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getSubscriptionServiceSet().onPublish(service); - } - - @Override - public void onRepublish(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getRepublishCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getSubscriptionServiceSet().onRepublish(service); - } - - @Override - public void onTransferSubscriptions(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getTransferSubscriptionsCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getSubscriptionServiceSet().onTransferSubscriptions(service); - } - - @Override - public void onDeleteSubscriptions(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getDeleteSubscriptionsCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getSubscriptionServiceSet().onDeleteSubscriptions(service); - } - //endregion - - //region MonitoredItem Services - @Override - public void onCreateMonitoredItems(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getCreateMonitoredItemsCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getMonitoredItemServiceSet().onCreateMonitoredItems(service); - } - - @Override - public void onModifyMonitoredItems(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getModifyMonitoredItemsCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getMonitoredItemServiceSet().onModifyMonitoredItems(service); - } - - @Override - public void onSetMonitoringMode(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getSetMonitoringModeCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getMonitoredItemServiceSet().onSetMonitoringMode(service); - } - - @Override - public void onSetTriggering(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getSetTriggeringCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getMonitoredItemServiceSet().onSetTriggering(service); - } - - @Override - public void onDeleteMonitoredItems(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getDeleteMonitoredItemsCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getMonitoredItemServiceSet().onDeleteMonitoredItems(service); - } - //endregion - - //region Method Services - @Override - public void onCall(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getCallCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getMethodServiceSet().onCall(service); - } - //endregion - - //region Query Services - @Override - public void onQueryFirst(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getQueryFirstCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getQueryServiceSet().onQueryFirst(service); - } - - @Override - public void onQueryNext(ServiceRequest service) throws UaException { - Session session = session(service); - - session.getSessionDiagnostics().getQueryNextCount().record(service); - session.getSessionDiagnostics().getTotalRequestCount().record(service); - - session.getQueryServiceSet().onQueryNext(service); - } - //endregion } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/AddressSpaceComposite.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/AddressSpaceComposite.java index 6331aa7dd..16ad2f31b 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/AddressSpaceComposite.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/AddressSpaceComposite.java @@ -256,10 +256,13 @@ public void registerNodes(RegisterNodesContext context, List nodeIds) { asx.getFilter().filterRegisterNode(server, nodeId) ), (AddressSpace asx) -> group -> { - RegisterNodesContext ctx = new RegisterNodesContext( + var ctx = new RegisterNodesContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.registerNodes(ctx, group); @@ -280,10 +283,13 @@ public void unregisterNodes(UnregisterNodesContext context, List nodeIds asx.getFilter().filterUnregisterNode(server, nodeId) ), (AddressSpace asx) -> group -> { - UnregisterNodesContext ctx = new UnregisterNodesContext( + var ctx = new UnregisterNodesContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.unregisterNodes(ctx, group); @@ -321,10 +327,13 @@ public void read( asx.getFilter().filterRead(server, readValueId) ), (AddressSpace asx) -> group -> { - ReadContext ctx = new ReadContext( + var ctx = new ReadContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.read(ctx, maxAge, timestamps, group); @@ -350,10 +359,13 @@ public void write( ), (AddressSpace asx) -> group -> { - WriteContext ctx = new WriteContext( + var ctx = new WriteContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.write(ctx, group); @@ -385,10 +397,13 @@ public void historyRead( ), (AddressSpace asx) -> group -> { - HistoryReadContext ctx = new HistoryReadContext( + var ctx = new HistoryReadContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.historyRead( @@ -419,10 +434,13 @@ public void historyUpdate( ), (AddressSpace asx) -> group -> { - HistoryUpdateContext ctx = new HistoryUpdateContext( + var ctx = new HistoryUpdateContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.historyUpdate(ctx, group); @@ -452,10 +470,13 @@ public void call( ), (AddressSpace asx) -> group -> { - CallContext ctx = new CallContext( + var ctx = new CallContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.call(ctx, group); @@ -649,10 +670,13 @@ public void addNodes(AddNodesContext context, List nodesToAdd) { ), (AddressSpace asx) -> group -> { - AddNodesContext ctx = new AddNodesContext( + var ctx = new AddNodesContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.addNodes(ctx, group); @@ -674,10 +698,13 @@ public void deleteNodes(DeleteNodesContext context, List nodesT ), (AddressSpace asx) -> group -> { - DeleteNodesContext ctx = new DeleteNodesContext( + var ctx = new DeleteNodesContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.deleteNodes(ctx, group); @@ -699,10 +726,13 @@ public void addReferences(AddReferencesContext context, List ), (AddressSpace asx) -> group -> { - AddReferencesContext ctx = new AddReferencesContext( + var ctx = new AddReferencesContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.addReferences(ctx, group); @@ -724,10 +754,13 @@ public void deleteReferences(DeleteReferencesContext context, List group -> { - DeleteReferencesContext ctx = new DeleteReferencesContext( + var ctx = new DeleteReferencesContext( server, context.getSession().orElse(null), - context.getDiagnosticsContext() + context.getDiagnosticsContext(), + context.getAuditEntryId(), + context.getTimeoutHint(), + context.getAdditionalHeader() ); asx.deleteReferences(ctx, group); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/ServiceOperationContext.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/ServiceOperationContext.java index d270eea2d..cb45a2a1c 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/ServiceOperationContext.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/ServiceOperationContext.java @@ -16,31 +16,47 @@ import org.eclipse.milo.opcua.sdk.server.DiagnosticsContext; import org.eclipse.milo.opcua.sdk.server.OpcUaServer; import org.eclipse.milo.opcua.sdk.server.Session; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.jetbrains.annotations.Nullable; +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; + public class ServiceOperationContext extends AsyncOperationContext> implements AccessContext { private final Session session; private final DiagnosticsContext diagnosticsContext; + private final String auditEntryId; + + private final UInteger timeoutHint; + + private final ExtensionObject additionalHeader; + public ServiceOperationContext( OpcUaServer server, @Nullable Session session ) { - this(server, session, new DiagnosticsContext<>()); + this(server, session, new DiagnosticsContext<>(), "", uint(0), null); } public ServiceOperationContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader ) { super(server); this.session = session; this.diagnosticsContext = diagnosticsContext; + this.auditEntryId = auditEntryId; + this.timeoutHint = timeoutHint; + this.additionalHeader = additionalHeader; } /** @@ -55,4 +71,16 @@ public DiagnosticsContext getDiagnosticsContext() { return diagnosticsContext; } + public @Nullable String getAuditEntryId() { + return auditEntryId; + } + + public UInteger getTimeoutHint() { + return timeoutHint; + } + + public ExtensionObject getAdditionalHeader() { + return additionalHeader; + } + } diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/EndpointConfiguration.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/EndpointConfig.java similarity index 96% rename from opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/EndpointConfiguration.java rename to opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/EndpointConfig.java index 51a15e013..b0c190fd3 100644 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/EndpointConfiguration.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/EndpointConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.server; +package org.eclipse.milo.opcua.sdk.server.api.config; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -26,7 +26,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; import org.jetbrains.annotations.Nullable; -public class EndpointConfiguration { +public class EndpointConfig { private final TransportProfile transportProfile; private final String bindAddress; @@ -38,7 +38,7 @@ public class EndpointConfiguration { private final MessageSecurityMode securityMode; private final List tokenPolicies; - private EndpointConfiguration( + private EndpointConfig( TransportProfile transportProfile, String bindAddress, int bindPort, @@ -110,7 +110,7 @@ public String getEndpointUrl() { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - EndpointConfiguration that = (EndpointConfiguration) o; + EndpointConfig that = (EndpointConfig) o; return bindPort == that.bindPort && transportProfile == that.transportProfile && Objects.equal(bindAddress, that.bindAddress) && @@ -152,7 +152,7 @@ public String toString() { .toString(); } - public static EndpointConfiguration.Builder newBuilder() { + public static Builder newBuilder() { return new Builder(); } @@ -252,7 +252,7 @@ public Builder copy() { .addTokenPolicies(tokenPolicies); } - public EndpointConfiguration build() { + public EndpointConfig build() { if (securityPolicy != SecurityPolicy.None || securityMode != MessageSecurityMode.None) { @@ -285,7 +285,7 @@ public EndpointConfiguration build() { tokenPolicies.add(USER_TOKEN_POLICY_ANONYMOUS); } - return new EndpointConfiguration( + return new EndpointConfig( transportProfile, bindAddress, bindPort, diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfig.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfig.java index 40914b3ce..7618fb1df 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfig.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -10,6 +10,8 @@ package org.eclipse.milo.opcua.sdk.server.api.config; +import java.util.Set; +import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; @@ -19,13 +21,18 @@ import org.eclipse.milo.opcua.sdk.server.identity.IdentityValidator; import org.eclipse.milo.opcua.sdk.server.identity.UsernameIdentityValidator; import org.eclipse.milo.opcua.sdk.server.identity.X509IdentityValidator; +import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; +import org.eclipse.milo.opcua.stack.core.security.CertificateManager; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +import org.eclipse.milo.opcua.stack.core.security.ServerCertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.TrustListManager; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; +import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; import org.eclipse.milo.opcua.stack.core.types.structured.BuildInfo; import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; -import org.eclipse.milo.opcua.stack.server.UaStackServerConfig; -public interface OpcUaServerConfig extends UaStackServerConfig { +public interface OpcUaServerConfig { /** * A {@link UserTokenPolicy} for anonymous access. @@ -57,6 +64,45 @@ public interface OpcUaServerConfig extends UaStackServerConfig { SecurityPolicy.Basic256.getUri() ); + /** + * @return the {@link EndpointConfig}s for this server. + */ + Set getEndpoints(); + + /** + * Get the application name for the server. + *

+ * This will be used in the {@link ApplicationDescription} returned to clients. + * + * @return the application name for the server. + */ + LocalizedText getApplicationName(); + + /** + * Get the application uri for the server. + *

+ * This will be used in the {@link ApplicationDescription} returned to clients. + *

+ * The application uri must match the application uri used on the server's application instance certificate. + * + * @return the application uri for the server. + */ + String getApplicationUri(); + + /** + * Get the product uri for the server. + *

+ * This will be used in the {@link ApplicationDescription} returned to clients. + * + * @return the product uri for the server. + */ + String getProductUri(); + + /** + * @return the server {@link BuildInfo}. + */ + BuildInfo getBuildInfo(); + /** * Get the {@link IdentityValidator} for the server. * @@ -69,15 +115,35 @@ public interface OpcUaServerConfig extends UaStackServerConfig { IdentityValidator getIdentityValidator(); /** - * @return the server {@link BuildInfo}. + * @return the configured {@link EncodingLimits}. */ - BuildInfo getBuildInfo(); + EncodingLimits getEncodingLimits(); /** * @return the {@link OpcUaServerConfigLimits}. */ OpcUaServerConfigLimits getLimits(); + /** + * @return the {@link CertificateManager} for this server. + */ + CertificateManager getCertificateManager(); + + /** + * @return the {@link TrustListManager} for this server. + */ + TrustListManager getTrustListManager(); + + /** + * @return the {@link ServerCertificateValidator} for this server. + */ + ServerCertificateValidator getCertificateValidator(); + + /** + * @return the {@link ExecutorService} for this server. + */ + ExecutorService getExecutor(); + /** * @return the {@link ScheduledExecutorService} used by the {@link OpcUaServer} being configured. */ @@ -99,28 +165,21 @@ static OpcUaServerConfigBuilder builder() { * @return a {@link OpcUaServerConfigBuilder} pre-populated with values from {@code config}. */ static OpcUaServerConfigBuilder copy(OpcUaServerConfig config) { - OpcUaServerConfigBuilder builder = new OpcUaServerConfigBuilder(); + var builder = new OpcUaServerConfigBuilder(); - // UaStackServerConfig values builder.setEndpoints(config.getEndpoints()); builder.setApplicationName(config.getApplicationName()); builder.setApplicationUri(config.getApplicationUri()); builder.setProductUri(config.getProductUri()); + builder.setBuildInfo(config.getBuildInfo()); builder.setEncodingLimits(config.getEncodingLimits()); - builder.setMinimumSecureChannelLifetime(config.getMinimumSecureChannelLifetime()); - builder.setMaximumSecureChannelLifetime(config.getMaximumSecureChannelLifetime()); + builder.setLimits(config.getLimits()); + builder.setIdentityValidator(config.getIdentityValidator()); builder.setCertificateManager(config.getCertificateManager()); builder.setTrustListManager(config.getTrustListManager()); builder.setCertificateValidator(config.getCertificateValidator()); - builder.setHttpsKeyPair(config.getHttpsKeyPair().orElse(null)); - builder.setHttpsCertificateChain(config.getHttpsCertificateChain().orElse(null)); builder.setExecutor(config.getExecutor()); - - // OpcUaServerConfig values - builder.setIdentityValidator(config.getIdentityValidator()); - builder.setBuildInfo(config.getBuildInfo()); - builder.setLimits(config.getLimits()); - builder.setScheduledExecutorService(config.getScheduledExecutorService()); + builder.setScheduledExecutor(config.getScheduledExecutorService()); return builder; } @@ -133,10 +192,7 @@ static OpcUaServerConfigBuilder copy(OpcUaServerConfig config) { * @param consumer a {@link Consumer} that may modify the builder. * @return a {@link OpcUaServerConfig} built from the builder provided to {@code consumer}. */ - static OpcUaServerConfig copy( - OpcUaServerConfig config, - Consumer consumer) { - + static OpcUaServerConfig copy(OpcUaServerConfig config, Consumer consumer) { OpcUaServerConfigBuilder builder = copy(config); consumer.accept(builder); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfigBuilder.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfigBuilder.java index 5177bb766..c5f357b6c 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfigBuilder.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfigBuilder.java @@ -10,9 +10,7 @@ package org.eclipse.milo.opcua.sdk.server.api.config; -import java.security.KeyPair; -import java.security.cert.X509Certificate; -import java.util.Optional; +import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; @@ -22,19 +20,22 @@ import org.eclipse.milo.opcua.stack.core.Stack; import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; import org.eclipse.milo.opcua.stack.core.security.CertificateManager; +import org.eclipse.milo.opcua.stack.core.security.ServerCertificateValidator; import org.eclipse.milo.opcua.stack.core.security.TrustListManager; import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.structured.BuildInfo; -import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; -import org.eclipse.milo.opcua.stack.server.UaStackServerConfig; -import org.eclipse.milo.opcua.stack.server.UaStackServerConfigBuilder; -import org.eclipse.milo.opcua.stack.server.security.ServerCertificateValidator; -public class OpcUaServerConfigBuilder extends UaStackServerConfigBuilder { +public class OpcUaServerConfigBuilder { - private IdentityValidator identityValidator = AnonymousIdentityValidator.INSTANCE; + private Set endpoints = new HashSet<>(); + + private LocalizedText applicationName = LocalizedText + .english("server application name not configured"); + + private String applicationUri = "server application uri not configured"; + + private String productUri = "server product uri not configured"; private BuildInfo buildInfo = new BuildInfo( "", @@ -45,158 +46,155 @@ public class OpcUaServerConfigBuilder extends UaStackServerConfigBuilder { DateTime.MIN_VALUE ); - private OpcUaServerConfigLimits limits = new OpcUaServerConfigLimits() {}; + private IdentityValidator identityValidator = AnonymousIdentityValidator.INSTANCE; - private ScheduledExecutorService scheduledExecutorService; + private EncodingLimits encodingLimits = EncodingLimits.DEFAULT; - public OpcUaServerConfigBuilder setIdentityValidator(IdentityValidator identityValidator) { - this.identityValidator = identityValidator; - return this; - } + private OpcUaServerConfigLimits limits = new OpcUaServerConfigLimits() {}; - public OpcUaServerConfigBuilder setBuildInfo(BuildInfo buildInfo) { - this.buildInfo = buildInfo; - return this; - } + private CertificateManager certificateManager; + private TrustListManager trustListManager; + private ServerCertificateValidator certificateValidator; - public OpcUaServerConfigBuilder setLimits(OpcUaServerConfigLimits limits) { - this.limits = limits; - return this; - } + private ExecutorService executor; + private ScheduledExecutorService scheduledExecutor; - public OpcUaServerConfigBuilder setScheduledExecutorService(ScheduledExecutorService scheduledExecutorService) { - this.scheduledExecutorService = scheduledExecutorService; - return this; - } - @Override - public OpcUaServerConfigBuilder setEndpoints(Set endpointConfigurations) { - super.setEndpoints(endpointConfigurations); + public OpcUaServerConfigBuilder setEndpoints(Set endpointConfigs) { + this.endpoints = endpointConfigs; return this; } - @Override public OpcUaServerConfigBuilder setApplicationName(LocalizedText applicationName) { - super.setApplicationName(applicationName); + this.applicationName = applicationName; return this; } - @Override public OpcUaServerConfigBuilder setApplicationUri(String applicationUri) { - super.setApplicationUri(applicationUri); + this.applicationUri = applicationUri; return this; } - @Override public OpcUaServerConfigBuilder setProductUri(String productUri) { - super.setProductUri(productUri); - return this; - } - - @Override - public OpcUaServerConfigBuilder setCertificateManager(CertificateManager certificateManager) { - super.setCertificateManager(certificateManager); + this.productUri = productUri; return this; } - @Override - public OpcUaServerConfigBuilder setTrustListManager(TrustListManager trustListManager) { - super.setTrustListManager(trustListManager); + public OpcUaServerConfigBuilder setBuildInfo(BuildInfo buildInfo) { + this.buildInfo = buildInfo; return this; } - @Override - public OpcUaServerConfigBuilder setCertificateValidator(ServerCertificateValidator certificateValidator) { - super.setCertificateValidator(certificateValidator); + public OpcUaServerConfigBuilder setEncodingLimits(EncodingLimits encodingLimits) { + this.encodingLimits = encodingLimits; return this; } - @Override - public OpcUaServerConfigBuilder setHttpsKeyPair(KeyPair httpsKeyPair) { - super.setHttpsKeyPair(httpsKeyPair); + public OpcUaServerConfigBuilder setLimits(OpcUaServerConfigLimits limits) { + this.limits = limits; return this; } - /** - * @deprecated use {@link #setHttpsCertificateChain(X509Certificate[])} instead. - */ - @Override - @Deprecated - public OpcUaServerConfigBuilder setHttpsCertificate(X509Certificate httpsCertificate) { - super.setHttpsCertificate(httpsCertificate); + public OpcUaServerConfigBuilder setIdentityValidator(IdentityValidator identityValidator) { + this.identityValidator = identityValidator; return this; } - @Override - public OpcUaServerConfigBuilder setHttpsCertificateChain(X509Certificate[] httpsCertificate) { - super.setHttpsCertificateChain(httpsCertificate); + public OpcUaServerConfigBuilder setCertificateManager(CertificateManager certificateManager) { + this.certificateManager = certificateManager; return this; } - @Override - public OpcUaServerConfigBuilder setExecutor(ExecutorService executor) { - super.setExecutor(executor); + public OpcUaServerConfigBuilder setTrustListManager(TrustListManager trustListManager) { + this.trustListManager = trustListManager; return this; } - @Override - public OpcUaServerConfigBuilder setEncodingLimits(EncodingLimits encodingLimits) { - super.setEncodingLimits(encodingLimits); + public OpcUaServerConfigBuilder setCertificateValidator(ServerCertificateValidator certificateValidator) { + this.certificateValidator = certificateValidator; return this; } - @Override - public OpcUaServerConfigBuilder setMinimumSecureChannelLifetime(UInteger minimumSecureChannelLifetime) { - super.setMinimumSecureChannelLifetime(minimumSecureChannelLifetime); + public OpcUaServerConfigBuilder setExecutor(ExecutorService executor) { + this.executor = executor; return this; } - @Override - public OpcUaServerConfigBuilder setMaximumSecureChannelLifetime(UInteger maximumSecureChannelLifetime) { - super.setMaximumSecureChannelLifetime(maximumSecureChannelLifetime); + public OpcUaServerConfigBuilder setScheduledExecutor(ScheduledExecutorService scheduledExecutor) { + this.scheduledExecutor = scheduledExecutor; return this; } - @Override public OpcUaServerConfig build() { - UaStackServerConfig stackServerConfig = super.build(); - - ScheduledExecutorService scheduledExecutorService = this.scheduledExecutorService; - if (scheduledExecutorService == null) { - scheduledExecutorService = Stack.sharedScheduledExecutor(); + if (executor == null) { + executor = Stack.sharedExecutor(); + } + if (scheduledExecutor == null) { + scheduledExecutor = Stack.sharedScheduledExecutor(); } return new OpcUaServerConfigImpl( - stackServerConfig, - identityValidator, + endpoints, + applicationName, + applicationUri, + productUri, buildInfo, + identityValidator, + encodingLimits, limits, - scheduledExecutorService + certificateManager, + trustListManager, + certificateValidator, + executor, + scheduledExecutor ); } public static final class OpcUaServerConfigImpl implements OpcUaServerConfig { - private final UaStackServerConfig stackServerConfig; - - private final IdentityValidator identityValidator; + private final Set endpoints; + private final LocalizedText applicationName; + private final String applicationUri; + private final String productUri; private final BuildInfo buildInfo; + private final IdentityValidator identityValidator; + private final EncodingLimits encodingLimits; private final OpcUaServerConfigLimits limits; + private final CertificateManager certificateManager; + private final TrustListManager trustListManager; + private final ServerCertificateValidator certificateValidator; + private final ExecutorService executor; private final ScheduledExecutorService scheduledExecutorService; public OpcUaServerConfigImpl( - UaStackServerConfig stackServerConfig, - IdentityValidator identityValidator, + Set endpoints, + LocalizedText applicationName, + String applicationUri, + String productUri, BuildInfo buildInfo, + IdentityValidator identityValidator, + EncodingLimits encodingLimits, OpcUaServerConfigLimits limits, + CertificateManager certificateManager, + TrustListManager trustListManager, + ServerCertificateValidator certificateValidator, + ExecutorService executor, ScheduledExecutorService scheduledExecutorService ) { - this.stackServerConfig = stackServerConfig; - this.identityValidator = identityValidator; + this.endpoints = endpoints; + this.applicationName = applicationName; + this.applicationUri = applicationUri; + this.productUri = productUri; this.buildInfo = buildInfo; + this.identityValidator = identityValidator; + this.encodingLimits = encodingLimits; this.limits = limits; + this.certificateManager = certificateManager; + this.trustListManager = trustListManager; + this.certificateValidator = certificateValidator; + this.executor = executor; this.scheduledExecutorService = scheduledExecutorService; } @@ -211,78 +209,58 @@ public BuildInfo getBuildInfo() { } @Override - public OpcUaServerConfigLimits getLimits() { - return limits; - } - - @Override - public ScheduledExecutorService getScheduledExecutorService() { - return scheduledExecutorService; - } - - @Override - public Set getEndpoints() { - return stackServerConfig.getEndpoints(); + public Set getEndpoints() { + return endpoints; } @Override public LocalizedText getApplicationName() { - return stackServerConfig.getApplicationName(); + return applicationName; } @Override public String getApplicationUri() { - return stackServerConfig.getApplicationUri(); + return applicationUri; } @Override public String getProductUri() { - return stackServerConfig.getProductUri(); + return productUri; } @Override - public CertificateManager getCertificateManager() { - return stackServerConfig.getCertificateManager(); + public EncodingLimits getEncodingLimits() { + return encodingLimits; } @Override - public TrustListManager getTrustListManager() { - return stackServerConfig.getTrustListManager(); + public OpcUaServerConfigLimits getLimits() { + return limits; } @Override - public ServerCertificateValidator getCertificateValidator() { - return stackServerConfig.getCertificateValidator(); + public CertificateManager getCertificateManager() { + return certificateManager; } @Override - public Optional getHttpsKeyPair() { - return stackServerConfig.getHttpsKeyPair(); + public TrustListManager getTrustListManager() { + return trustListManager; } @Override - public Optional getHttpsCertificateChain() { - return stackServerConfig.getHttpsCertificateChain(); + public ServerCertificateValidator getCertificateValidator() { + return certificateValidator; } @Override public ExecutorService getExecutor() { - return stackServerConfig.getExecutor(); + return executor; } @Override - public EncodingLimits getEncodingLimits() { - return stackServerConfig.getEncodingLimits(); - } - - @Override - public UInteger getMinimumSecureChannelLifetime() { - return stackServerConfig.getMinimumSecureChannelLifetime(); - } - - @Override - public UInteger getMaximumSecureChannelLifetime() { - return stackServerConfig.getMaximumSecureChannelLifetime(); + public ScheduledExecutorService getScheduledExecutorService() { + return scheduledExecutorService; } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/AttributeHistoryServices.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/AttributeHistoryServices.java index 2c8bd0314..c153c08b0 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/AttributeHistoryServices.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/AttributeHistoryServices.java @@ -18,7 +18,9 @@ import org.eclipse.milo.opcua.sdk.server.Session; import org.eclipse.milo.opcua.sdk.server.api.ServiceOperationContext; import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadDetails; import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadResult; @@ -81,9 +83,13 @@ public HistoryReadContext(OpcUaServer server, @Nullable Session session) { public HistoryReadContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext) { + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader + ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } @@ -97,10 +103,13 @@ public HistoryUpdateContext(OpcUaServer server, @Nullable Session session) { public HistoryUpdateContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/AttributeServices.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/AttributeServices.java index cc7327c14..1fddcf556 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/AttributeServices.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/AttributeServices.java @@ -17,7 +17,9 @@ import org.eclipse.milo.opcua.sdk.server.Session; import org.eclipse.milo.opcua.sdk.server.api.ServiceOperationContext; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue; @@ -35,10 +37,7 @@ public interface AttributeServices { * @param timestamps requested timestamp values. * @param readValueIds the values to read. */ - void read(ReadContext context, - Double maxAge, - TimestampsToReturn timestamps, - List readValueIds); + void read(ReadContext context, Double maxAge, TimestampsToReturn timestamps, List readValueIds); /** * Write one or more values to nodes belonging to this {@link AttributeServices}. @@ -59,10 +58,13 @@ public ReadContext(OpcUaServer server, @Nullable Session session) { public ReadContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } @@ -76,10 +78,13 @@ public WriteContext(OpcUaServer server, @Nullable Session session) { public WriteContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/MethodServices.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/MethodServices.java index eb572d2cf..5611282aa 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/MethodServices.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/MethodServices.java @@ -18,8 +18,10 @@ import org.eclipse.milo.opcua.sdk.server.api.ServiceOperationContext; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodRequest; import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodResult; import org.jetbrains.annotations.Nullable; @@ -54,10 +56,13 @@ public CallContext(OpcUaServer server, @Nullable Session session) { public CallContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/NodeManagementServices.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/NodeManagementServices.java index b6013a062..ed50ac1dd 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/NodeManagementServices.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/NodeManagementServices.java @@ -18,8 +18,10 @@ import org.eclipse.milo.opcua.sdk.server.Session; import org.eclipse.milo.opcua.sdk.server.api.ServiceOperationContext; import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesItem; import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesResult; import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesItem; @@ -65,10 +67,13 @@ public AddNodesContext(OpcUaServer server, @Nullable Session session) { public AddNodesContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } @@ -82,9 +87,13 @@ public DeleteNodesContext(OpcUaServer server, @Nullable Session session) { public DeleteNodesContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext) { + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader + ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } @@ -98,10 +107,13 @@ public AddReferencesContext(OpcUaServer server, @Nullable Session session) { public AddReferencesContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } @@ -115,9 +127,13 @@ public DeleteReferencesContext(OpcUaServer server, @Nullable Session session) { public DeleteReferencesContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext) { + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader + ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/ViewServices.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/ViewServices.java index 9899ac16c..98de5551c 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/ViewServices.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/services/ViewServices.java @@ -23,6 +23,7 @@ import org.eclipse.milo.opcua.sdk.server.api.ServiceOperationContext; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; @@ -130,10 +131,13 @@ public RegisterNodesContext(OpcUaServer server, @Nullable Session session) { public RegisterNodesContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } @@ -147,10 +151,13 @@ public UnregisterNodesContext(OpcUaServer server, @Nullable Session session) { public UnregisterNodesContext( OpcUaServer server, @Nullable Session session, - DiagnosticsContext diagnosticsContext + DiagnosticsContext diagnosticsContext, + @Nullable String auditEntryId, + UInteger timeoutHint, + ExtensionObject additionalHeader ) { - super(server, session, diagnosticsContext); + super(server, session, diagnosticsContext, auditEntryId, timeoutHint, additionalHeader); } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/diagnostics/ServerDiagnosticsSummary.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/diagnostics/ServerDiagnosticsSummary.java index ee5c5308d..799877482 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/diagnostics/ServerDiagnosticsSummary.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/diagnostics/ServerDiagnosticsSummary.java @@ -28,6 +28,10 @@ public class ServerDiagnosticsSummary { private final LongAdder sessionAbortCount = new LongAdder(); private final LongAdder cumulatedSubscriptionCount = new LongAdder(); + private final LongAdder securityRejectedRequestCount = new LongAdder(); + + private final LongAdder rejectedRequestCount = new LongAdder(); + private final OpcUaServer server; public ServerDiagnosticsSummary(OpcUaServer server) { @@ -122,7 +126,7 @@ public UInteger getPublishingIntervalCount() { * restarted). The requests include all Services defined in Part 4, and also requests to create sessions. */ public UInteger getSecurityRejectedRequestCount() { - return uint(server.getStackServer().getSecurityRejectedRequestCount().sum()); + return uint(securityRejectedRequestCount.sum()); } /** @@ -132,7 +136,7 @@ public UInteger getSecurityRejectedRequestCount() { * @see #getSecurityRejectedRequestCount() */ public UInteger getRejectedRequestCount() { - return uint(server.getStackServer().getRejectedRequestCount().sum()); + return uint(rejectedRequestCount.sum()); } /** diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/diagnostics/ServiceCounter.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/diagnostics/ServiceCounter.java index eb2c19fa7..7e7a306b2 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/diagnostics/ServiceCounter.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/diagnostics/ServiceCounter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -10,10 +10,10 @@ package org.eclipse.milo.opcua.sdk.server.diagnostics; +import java.util.concurrent.CompletionStage; import java.util.concurrent.atomic.LongAdder; import org.eclipse.milo.opcua.stack.core.types.structured.ServiceCounterDataType; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; @@ -22,8 +22,8 @@ public class ServiceCounter { private final LongAdder totalCount = new LongAdder(); private final LongAdder errorCount = new LongAdder(); - public void record(ServiceRequest service) { - service.getFuture().whenComplete((r, ex) -> { + public void record(CompletionStage completionStage) { + completionStage.whenComplete((r, ex) -> { totalCount.increment(); if (ex != null) { diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/ObjectTypeInitializer.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/ObjectTypeInitializer.java index f9704f160..c36f571db 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/ObjectTypeInitializer.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/ObjectTypeInitializer.java @@ -18,9 +18,11 @@ import org.eclipse.milo.opcua.sdk.server.model.objects.AlarmConditionTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.AlarmGroupTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.AlarmMetricsTypeNode; +import org.eclipse.milo.opcua.sdk.server.model.objects.AlarmSuppressionGroupTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.AliasNameCategoryTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.AliasNameTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.ApplicationCertificateTypeNode; +import org.eclipse.milo.opcua.sdk.server.model.objects.ApplicationConfigurationTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.AuditActivateSessionEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.AuditAddNodesEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.AuditAddReferencesEventTypeNode; @@ -83,6 +85,7 @@ import org.eclipse.milo.opcua.sdk.server.model.objects.CertificateGroupFolderTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.CertificateGroupTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.CertificateTypeNode; +import org.eclipse.milo.opcua.sdk.server.model.objects.CertificateUpdateRequestedAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.CertificateUpdatedAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.ChoiceStateTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.ConditionTypeNode; @@ -179,6 +182,7 @@ import org.eclipse.milo.opcua.sdk.server.model.objects.ProgramTransitionAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.ProgramTransitionEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.ProgressEventTypeNode; +import org.eclipse.milo.opcua.sdk.server.model.objects.ProvisionableDeviceTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.PubSubCapabilitiesTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.PubSubCommunicationFailureEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.PubSubConfigurationTypeNode; @@ -240,12 +244,14 @@ import org.eclipse.milo.opcua.sdk.server.model.objects.TemporaryFileTransferTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.TestingConditionClassTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.TrainingConditionClassTypeNode; +import org.eclipse.milo.opcua.sdk.server.model.objects.TransactionDiagnosticsTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.TransitionEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.TransitionTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.TransparentRedundancyTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.TripAlarmTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.TrustListOutOfDateAlarmTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.TrustListTypeNode; +import org.eclipse.milo.opcua.sdk.server.model.objects.TrustListUpdateRequestedAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.TrustListUpdatedAuditEventTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.UadpDataSetReaderMessageTypeNode; import org.eclipse.milo.opcua.sdk.server.model.objects.UadpDataSetWriterMessageTypeNode; @@ -299,6 +305,12 @@ public static void initialize(NamespaceTable namespaceTable, AlarmGroupTypeNode.class, AlarmGroupTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=32064") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + AlarmSuppressionGroupTypeNode.class, + AlarmSuppressionGroupTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=13813") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -750,16 +762,16 @@ public static void initialize(NamespaceTable namespaceTable, AuditConditionOutOfServiceEventTypeNode::new ); objectTypeManager.registerObjectType( - NodeId.parse("i=12561") + NodeId.parse("i=32260") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), - TrustListUpdatedAuditEventTypeNode.class, - TrustListUpdatedAuditEventTypeNode::new + TrustListUpdateRequestedAuditEventTypeNode.class, + TrustListUpdateRequestedAuditEventTypeNode::new ); objectTypeManager.registerObjectType( - NodeId.parse("i=12620") + NodeId.parse("i=32306") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), - CertificateUpdatedAuditEventTypeNode.class, - CertificateUpdatedAuditEventTypeNode::new + CertificateUpdateRequestedAuditEventTypeNode.class, + CertificateUpdateRequestedAuditEventTypeNode::new ); objectTypeManager.registerObjectType( NodeId.parse("i=18011") @@ -791,6 +803,18 @@ public static void initialize(NamespaceTable namespaceTable, AuditClientUpdateMethodResultEventTypeNode.class, AuditClientUpdateMethodResultEventTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=12561") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + TrustListUpdatedAuditEventTypeNode.class, + TrustListUpdatedAuditEventTypeNode::new + ); + objectTypeManager.registerObjectType( + NodeId.parse("i=12620") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + CertificateUpdatedAuditEventTypeNode.class, + CertificateUpdatedAuditEventTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=2130") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -1385,12 +1409,24 @@ public static void initialize(NamespaceTable namespaceTable, UserCredentialCertificateTypeNode.class, UserCredentialCertificateTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=32286") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + TransactionDiagnosticsTypeNode.class, + TransactionDiagnosticsTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=12581") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), ServerConfigurationTypeNode.class, ServerConfigurationTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=25731") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + ApplicationConfigurationTypeNode.class, + ApplicationConfigurationTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=18001") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -1511,12 +1547,6 @@ public static void initialize(NamespaceTable namespaceTable, DatagramWriterGroupTransportTypeNode.class, DatagramWriterGroupTransportTypeNode::new ); - objectTypeManager.registerObjectType( - NodeId.parse("i=24016") - .reindex(namespaceTable, "http://opcfoundation.org/UA/"), - DatagramDataSetReaderTransportTypeNode.class, - DatagramDataSetReaderTransportTypeNode::new - ); objectTypeManager.registerObjectType( NodeId.parse("i=21136") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -1601,6 +1631,12 @@ public static void initialize(NamespaceTable namespaceTable, DataSetReaderTransportTypeNode.class, DataSetReaderTransportTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=24016") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + DatagramDataSetReaderTransportTypeNode.class, + DatagramDataSetReaderTransportTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=21142") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -1727,6 +1763,12 @@ public static void initialize(NamespaceTable namespaceTable, UserManagementTypeNode.class, UserManagementTypeNode::new ); + objectTypeManager.registerObjectType( + NodeId.parse("i=26871") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + ProvisionableDeviceTypeNode.class, + ProvisionableDeviceTypeNode::new + ); objectTypeManager.registerObjectType( NodeId.parse("i=25221") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/VariableTypeInitializer.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/VariableTypeInitializer.java index 13c45877b..84b36400c 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/VariableTypeInitializer.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/VariableTypeInitializer.java @@ -12,6 +12,7 @@ import org.eclipse.milo.opcua.sdk.server.VariableTypeManager; import org.eclipse.milo.opcua.sdk.server.model.variables.AlarmRateVariableTypeNode; +import org.eclipse.milo.opcua.sdk.server.model.variables.AlarmStateVariableTypeNode; import org.eclipse.milo.opcua.sdk.server.model.variables.AnalogItemTypeNode; import org.eclipse.milo.opcua.sdk.server.model.variables.AnalogUnitRangeTypeNode; import org.eclipse.milo.opcua.sdk.server.model.variables.AnalogUnitTypeNode; @@ -47,6 +48,7 @@ import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyTypeNode; import org.eclipse.milo.opcua.sdk.server.model.variables.PubSubDiagnosticsCounterTypeNode; import org.eclipse.milo.opcua.sdk.server.model.variables.RationalNumberTypeNode; +import org.eclipse.milo.opcua.sdk.server.model.variables.ReferenceDescriptionVariableTypeNode; import org.eclipse.milo.opcua.sdk.server.model.variables.SamplingIntervalDiagnosticsArrayTypeNode; import org.eclipse.milo.opcua.sdk.server.model.variables.SamplingIntervalDiagnosticsTypeNode; import org.eclipse.milo.opcua.sdk.server.model.variables.SelectionListTypeNode; @@ -406,6 +408,12 @@ public static void initialize(NamespaceTable namespaceTable, AlarmRateVariableTypeNode.class, AlarmRateVariableTypeNode::new ); + variableTypeManager.registerVariableType( + NodeId.parse("i=32244") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + AlarmStateVariableTypeNode.class, + AlarmStateVariableTypeNode::new + ); variableTypeManager.registerVariableType( NodeId.parse("i=2380") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), @@ -424,6 +432,12 @@ public static void initialize(NamespaceTable namespaceTable, PubSubDiagnosticsCounterTypeNode.class, PubSubDiagnosticsCounterTypeNode::new ); + variableTypeManager.registerVariableType( + NodeId.parse("i=32657") + .reindex(namespaceTable, "http://opcfoundation.org/UA/"), + ReferenceDescriptionVariableTypeNode.class, + ReferenceDescriptionVariableTypeNode::new + ); variableTypeManager.registerVariableType( NodeId.parse("i=68") .reindex(namespaceTable, "http://opcfoundation.org/UA/"), diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AggregateConfigurationType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AggregateConfigurationType.java index e8f765913..7b81619dc 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AggregateConfigurationType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AggregateConfigurationType.java @@ -15,6 +15,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part13/4.2.1/#4.2.1.2 + */ public interface AggregateConfigurationType extends BaseObjectType { QualifiedProperty TREAT_UNCERTAIN_AS_BAD = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AggregateFunctionType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AggregateFunctionType.java index 847d24ade..f29421444 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AggregateFunctionType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AggregateFunctionType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part5/6.8 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part13/4.2.2/#4.2.2.2 */ public interface AggregateFunctionType extends BaseObjectType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmMetricsType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmMetricsType.java index acce3b55d..829a01176 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmMetricsType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmMetricsType.java @@ -22,7 +22,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.Argument; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/8.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/9.2 */ public interface AlarmMetricsType extends BaseObjectType { BaseDataVariableType getAlarmCountNode(); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmSuppressionGroupType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmSuppressionGroupType.java new file mode 100644 index 000000000..a7a553222 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmSuppressionGroupType.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.4 + */ +public interface AlarmSuppressionGroupType extends AlarmGroupType { +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmSuppressionGroupTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmSuppressionGroupTypeNode.java new file mode 100644 index 000000000..9ebaa5acf --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AlarmSuppressionGroupTypeNode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class AlarmSuppressionGroupTypeNode extends AlarmGroupTypeNode implements AlarmSuppressionGroupType { + public AlarmSuppressionGroupTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } + + public AlarmSuppressionGroupTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions); + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationCertificateType.java index 6ff3f0fe9..6112b3ef6 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationCertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.2 + */ public interface ApplicationCertificateType extends CertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationConfigurationType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationConfigurationType.java new file mode 100644 index 000000000..468a533e8 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationConfigurationType.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyType; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part21/9.3.6 + */ +public interface ApplicationConfigurationType extends ServerConfigurationType { + QualifiedProperty APPLICATION_URI = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ApplicationUri", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23751"), + -1, + String.class + ); + + QualifiedProperty PRODUCT_URI = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ProductUri", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23751"), + -1, + String.class + ); + + QualifiedProperty APPLICATION_TYPE = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ApplicationType", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=307"), + -1, + ApplicationType.class + ); + + QualifiedProperty ENABLED = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "Enabled", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + + String getApplicationUri(); + + void setApplicationUri(String value); + + PropertyType getApplicationUriNode(); + + String getProductUri(); + + void setProductUri(String value); + + PropertyType getProductUriNode(); + + ApplicationType getApplicationType(); + + void setApplicationType(ApplicationType value); + + PropertyType getApplicationTypeNode(); + + Boolean getEnabled(); + + void setEnabled(Boolean value); + + PropertyType getEnabledNode(); +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationConfigurationTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationConfigurationTypeNode.java new file mode 100644 index 000000000..3f00f1ee6 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ApplicationConfigurationTypeNode.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +import java.util.Optional; + +import org.eclipse.milo.opcua.sdk.core.nodes.VariableNode; +import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyTypeNode; +import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class ApplicationConfigurationTypeNode extends ServerConfigurationTypeNode implements ApplicationConfigurationType { + public ApplicationConfigurationTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } + + public ApplicationConfigurationTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions); + } + + @Override + public PropertyTypeNode getApplicationUriNode() { + Optional propertyNode = getPropertyNode(ApplicationConfigurationType.APPLICATION_URI); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public String getApplicationUri() { + return getProperty(ApplicationConfigurationType.APPLICATION_URI).orElse(null); + } + + @Override + public void setApplicationUri(String value) { + setProperty(ApplicationConfigurationType.APPLICATION_URI, value); + } + + @Override + public PropertyTypeNode getProductUriNode() { + Optional propertyNode = getPropertyNode(ApplicationConfigurationType.PRODUCT_URI); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public String getProductUri() { + return getProperty(ApplicationConfigurationType.PRODUCT_URI).orElse(null); + } + + @Override + public void setProductUri(String value) { + setProperty(ApplicationConfigurationType.PRODUCT_URI, value); + } + + @Override + public PropertyTypeNode getApplicationTypeNode() { + Optional propertyNode = getPropertyNode(ApplicationConfigurationType.APPLICATION_TYPE); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public ApplicationType getApplicationType() { + return getProperty(ApplicationConfigurationType.APPLICATION_TYPE).orElse(null); + } + + @Override + public void setApplicationType(ApplicationType value) { + setProperty(ApplicationConfigurationType.APPLICATION_TYPE, value); + } + + @Override + public PropertyTypeNode getEnabledNode() { + Optional propertyNode = getPropertyNode(ApplicationConfigurationType.ENABLED); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public Boolean getEnabled() { + return getProperty(ApplicationConfigurationType.ENABLED).orElse(null); + } + + @Override + public void setEnabled(Boolean value) { + setProperty(ApplicationConfigurationType.ENABLED, value); + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryAnnotationUpdateEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryAnnotationUpdateEventType.java index 2170891ac..37fa10dc8 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryAnnotationUpdateEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryAnnotationUpdateEventType.java @@ -17,7 +17,7 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.PerformUpdateType; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.4 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.4 */ public interface AuditHistoryAnnotationUpdateEventType extends AuditHistoryUpdateEventType { QualifiedProperty PERFORM_INSERT_REPLACE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryAtTimeDeleteEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryAtTimeDeleteEventType.java index 861d02df8..c715aee49 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryAtTimeDeleteEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryAtTimeDeleteEventType.java @@ -17,7 +17,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.7 */ public interface AuditHistoryAtTimeDeleteEventType extends AuditHistoryDeleteEventType { QualifiedProperty REQ_TIMES = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryDeleteEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryDeleteEventType.java index 92def58de..5b1712fd1 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryDeleteEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryDeleteEventType.java @@ -16,7 +16,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.5 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.5 */ public interface AuditHistoryDeleteEventType extends AuditHistoryUpdateEventType { QualifiedProperty UPDATED_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryEventDeleteEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryEventDeleteEventType.java index 9ed835007..d10e1412c 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryEventDeleteEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryEventDeleteEventType.java @@ -17,7 +17,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.HistoryEventFieldList; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.8 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.8 */ public interface AuditHistoryEventDeleteEventType extends AuditHistoryDeleteEventType { QualifiedProperty EVENT_IDS = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryEventUpdateEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryEventUpdateEventType.java index 56a7a7f16..602406908 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryEventUpdateEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryEventUpdateEventType.java @@ -19,7 +19,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.HistoryEventFieldList; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.2 */ public interface AuditHistoryEventUpdateEventType extends AuditHistoryUpdateEventType { QualifiedProperty UPDATED_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryRawModifyDeleteEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryRawModifyDeleteEventType.java index 1d1a7c62a..54335b031 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryRawModifyDeleteEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryRawModifyDeleteEventType.java @@ -17,7 +17,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.6 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.6 */ public interface AuditHistoryRawModifyDeleteEventType extends AuditHistoryDeleteEventType { QualifiedProperty IS_DELETE_MODIFIED = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryValueUpdateEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryValueUpdateEventType.java index dffbbb5bb..9a6dbf812 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryValueUpdateEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuditHistoryValueUpdateEventType.java @@ -18,7 +18,7 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.PerformUpdateType; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.6.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.6.3 */ public interface AuditHistoryValueUpdateEventType extends AuditHistoryUpdateEventType { QualifiedProperty UPDATED_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuthorizationServiceConfigurationType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuthorizationServiceConfigurationType.java index a13c7af1b..db084e2c9 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuthorizationServiceConfigurationType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuthorizationServiceConfigurationType.java @@ -15,6 +15,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/9.7.4 + */ public interface AuthorizationServiceConfigurationType extends BaseObjectType { QualifiedProperty SERVICE_URI = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuthorizationServicesConfigurationFolderType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuthorizationServicesConfigurationFolderType.java index fb5e92d42..041ff6ed7 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuthorizationServicesConfigurationFolderType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/AuthorizationServicesConfigurationFolderType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/9.7.2 + */ public interface AuthorizationServicesConfigurationFolderType extends FolderType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/BaseEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/BaseEventType.java index 0562f6fe5..f95106410 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/BaseEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/BaseEventType.java @@ -96,6 +96,38 @@ public interface BaseEventType extends BaseObjectType { UShort.class ); + QualifiedProperty CONDITION_CLASS_ID = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConditionClassId", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + -1, + NodeId.class + ); + + QualifiedProperty CONDITION_CLASS_NAME = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConditionClassName", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=21"), + -1, + LocalizedText.class + ); + + QualifiedProperty CONDITION_SUB_CLASS_ID = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConditionSubClassId", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + 1, + NodeId[].class + ); + + QualifiedProperty CONDITION_SUB_CLASS_NAME = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConditionSubClassName", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=21"), + 1, + LocalizedText[].class + ); + ByteString getEventId(); void setEventId(ByteString value); @@ -149,4 +181,28 @@ public interface BaseEventType extends BaseObjectType { void setSeverity(UShort value); PropertyType getSeverityNode(); + + NodeId getConditionClassId(); + + void setConditionClassId(NodeId value); + + PropertyType getConditionClassIdNode(); + + LocalizedText getConditionClassName(); + + void setConditionClassName(LocalizedText value); + + PropertyType getConditionClassNameNode(); + + NodeId[] getConditionSubClassId(); + + void setConditionSubClassId(NodeId[] value); + + PropertyType getConditionSubClassIdNode(); + + LocalizedText[] getConditionSubClassName(); + + void setConditionSubClassName(LocalizedText[] value); + + PropertyType getConditionSubClassNameNode(); } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/BaseEventTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/BaseEventTypeNode.java index fa6de25f6..6a51a3b81 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/BaseEventTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/BaseEventTypeNode.java @@ -186,4 +186,68 @@ public UShort getSeverity() { public void setSeverity(UShort value) { setProperty(BaseEventType.SEVERITY, value); } + + @Override + public PropertyTypeNode getConditionClassIdNode() { + Optional propertyNode = getPropertyNode(BaseEventType.CONDITION_CLASS_ID); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public NodeId getConditionClassId() { + return getProperty(BaseEventType.CONDITION_CLASS_ID).orElse(null); + } + + @Override + public void setConditionClassId(NodeId value) { + setProperty(BaseEventType.CONDITION_CLASS_ID, value); + } + + @Override + public PropertyTypeNode getConditionClassNameNode() { + Optional propertyNode = getPropertyNode(BaseEventType.CONDITION_CLASS_NAME); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public LocalizedText getConditionClassName() { + return getProperty(BaseEventType.CONDITION_CLASS_NAME).orElse(null); + } + + @Override + public void setConditionClassName(LocalizedText value) { + setProperty(BaseEventType.CONDITION_CLASS_NAME, value); + } + + @Override + public PropertyTypeNode getConditionSubClassIdNode() { + Optional propertyNode = getPropertyNode(BaseEventType.CONDITION_SUB_CLASS_ID); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public NodeId[] getConditionSubClassId() { + return getProperty(BaseEventType.CONDITION_SUB_CLASS_ID).orElse(null); + } + + @Override + public void setConditionSubClassId(NodeId[] value) { + setProperty(BaseEventType.CONDITION_SUB_CLASS_ID, value); + } + + @Override + public PropertyTypeNode getConditionSubClassNameNode() { + Optional propertyNode = getPropertyNode(BaseEventType.CONDITION_SUB_CLASS_NAME); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public LocalizedText[] getConditionSubClassName() { + return getProperty(BaseEventType.CONDITION_SUB_CLASS_NAME).orElse(null); + } + + @Override + public void setConditionSubClassName(LocalizedText[] value) { + setProperty(BaseEventType.CONDITION_SUB_CLASS_NAME, value); + } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateExpirationAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateExpirationAlarmType.java index c3e026ca7..dfdbb8a91 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateExpirationAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateExpirationAlarmType.java @@ -18,7 +18,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.7 */ public interface CertificateExpirationAlarmType extends SystemOffNormalAlarmType { QualifiedProperty EXPIRATION_DATE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupFolderType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupFolderType.java index 59fa40119..8dc79165a 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupFolderType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupFolderType.java @@ -10,6 +10,9 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.3/#7.8.3.3 + */ public interface CertificateGroupFolderType extends FolderType { CertificateGroupType getDefaultApplicationGroupNode(); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupFolderTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupFolderTypeNode.java index fd88b4f3f..7847bef62 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupFolderTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupFolderTypeNode.java @@ -12,10 +12,8 @@ import java.util.Optional; -import org.eclipse.milo.opcua.sdk.core.Reference; -import org.eclipse.milo.opcua.sdk.server.nodes.UaNode; +import org.eclipse.milo.opcua.sdk.core.nodes.ObjectNode; import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; -import org.eclipse.milo.opcua.sdk.server.nodes.UaObjectNode; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; @@ -42,19 +40,19 @@ public CertificateGroupFolderTypeNode(UaNodeContext context, NodeId nodeId, @Override public CertificateGroupTypeNode getDefaultApplicationGroupNode() { - Optional node = findNode("http://opcfoundation.org/UA/", "DefaultApplicationGroup", n -> n instanceof UaObjectNode, Reference.ORGANIZES_PREDICATE); - return (CertificateGroupTypeNode) node.orElse(null); + Optional component = getObjectComponent("http://opcfoundation.org/UA/", "DefaultApplicationGroup"); + return (CertificateGroupTypeNode) component.orElse(null); } @Override public CertificateGroupTypeNode getDefaultHttpsGroupNode() { - Optional node = findNode("http://opcfoundation.org/UA/", "DefaultHttpsGroup", n -> n instanceof UaObjectNode, Reference.ORGANIZES_PREDICATE); - return (CertificateGroupTypeNode) node.orElse(null); + Optional component = getObjectComponent("http://opcfoundation.org/UA/", "DefaultHttpsGroup"); + return (CertificateGroupTypeNode) component.orElse(null); } @Override public CertificateGroupTypeNode getDefaultUserTokenGroupNode() { - Optional node = findNode("http://opcfoundation.org/UA/", "DefaultUserTokenGroup", n -> n instanceof UaObjectNode, Reference.ORGANIZES_PREDICATE); - return (CertificateGroupTypeNode) node.orElse(null); + Optional component = getObjectComponent("http://opcfoundation.org/UA/", "DefaultUserTokenGroup"); + return (CertificateGroupTypeNode) component.orElse(null); } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupType.java index cb6d82797..bc4f7c41e 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateGroupType.java @@ -27,6 +27,9 @@ import org.eclipse.milo.opcua.stack.core.types.structured.Argument; import org.eclipse.milo.opcua.stack.core.util.Lazy; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.3/#7.8.3.1 + */ public interface CertificateGroupType extends BaseObjectType { QualifiedProperty CERTIFICATE_TYPES = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateType.java index 8a52dda47..bbe12caf7 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.1 + */ public interface CertificateType extends BaseObjectType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdateRequestedAuditEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdateRequestedAuditEventType.java new file mode 100644 index 000000000..000663654 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdateRequestedAuditEventType.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.10.13 + */ +public interface CertificateUpdateRequestedAuditEventType extends AuditUpdateMethodEventType { +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdateRequestedAuditEventTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdateRequestedAuditEventTypeNode.java new file mode 100644 index 000000000..b5dea4160 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdateRequestedAuditEventTypeNode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class CertificateUpdateRequestedAuditEventTypeNode extends AuditUpdateMethodEventTypeNode implements CertificateUpdateRequestedAuditEventType { + public CertificateUpdateRequestedAuditEventTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } + + public CertificateUpdateRequestedAuditEventTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions); + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdatedAuditEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdatedAuditEventType.java index 6ac53dc3e..35512648a 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdatedAuditEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdatedAuditEventType.java @@ -15,7 +15,10 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; -public interface CertificateUpdatedAuditEventType extends AuditUpdateMethodEventType { +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.10.14 + */ +public interface CertificateUpdatedAuditEventType extends AuditEventType { QualifiedProperty CERTIFICATE_GROUP = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "CertificateGroup", diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdatedAuditEventTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdatedAuditEventTypeNode.java index bc3e67f1d..4092416a6 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdatedAuditEventTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/CertificateUpdatedAuditEventTypeNode.java @@ -23,7 +23,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; -public class CertificateUpdatedAuditEventTypeNode extends AuditUpdateMethodEventTypeNode implements CertificateUpdatedAuditEventType { +public class CertificateUpdatedAuditEventTypeNode extends AuditEventTypeNode implements CertificateUpdatedAuditEventType { public CertificateUpdatedAuditEventTypeNode(UaNodeContext context, NodeId nodeId, QualifiedName browseName, LocalizedText displayName, LocalizedText description, UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ConditionType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ConditionType.java index 34e23430f..d1ee9561c 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ConditionType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ConditionType.java @@ -50,22 +50,6 @@ public interface ConditionType extends BaseEventType { LocalizedText.class ); - QualifiedProperty CONDITION_SUB_CLASS_ID = new QualifiedProperty<>( - "http://opcfoundation.org/UA/", - "ConditionSubClassId", - ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), - 1, - NodeId[].class - ); - - QualifiedProperty CONDITION_SUB_CLASS_NAME = new QualifiedProperty<>( - "http://opcfoundation.org/UA/", - "ConditionSubClassName", - ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=21"), - 1, - LocalizedText[].class - ); - QualifiedProperty CONDITION_NAME = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "ConditionName", @@ -90,6 +74,14 @@ public interface ConditionType extends BaseEventType { Boolean.class ); + QualifiedProperty SUPPORTS_FILTERED_RETAIN = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "SupportsFilteredRetain", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + QualifiedProperty CLIENT_USER_ID = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "ClientUserId", @@ -110,18 +102,6 @@ public interface ConditionType extends BaseEventType { PropertyType getConditionClassNameNode(); - NodeId[] getConditionSubClassId(); - - void setConditionSubClassId(NodeId[] value); - - PropertyType getConditionSubClassIdNode(); - - LocalizedText[] getConditionSubClassName(); - - void setConditionSubClassName(LocalizedText[] value); - - PropertyType getConditionSubClassNameNode(); - String getConditionName(); void setConditionName(String value); @@ -140,6 +120,12 @@ public interface ConditionType extends BaseEventType { PropertyType getRetainNode(); + Boolean getSupportsFilteredRetain(); + + void setSupportsFilteredRetain(Boolean value); + + PropertyType getSupportsFilteredRetainNode(); + String getClientUserId(); void setClientUserId(String value); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ConditionTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ConditionTypeNode.java index 2dd13fc18..6eb76cce4 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ConditionTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ConditionTypeNode.java @@ -80,38 +80,6 @@ public void setConditionClassName(LocalizedText value) { setProperty(ConditionType.CONDITION_CLASS_NAME, value); } - @Override - public PropertyTypeNode getConditionSubClassIdNode() { - Optional propertyNode = getPropertyNode(ConditionType.CONDITION_SUB_CLASS_ID); - return (PropertyTypeNode) propertyNode.orElse(null); - } - - @Override - public NodeId[] getConditionSubClassId() { - return getProperty(ConditionType.CONDITION_SUB_CLASS_ID).orElse(null); - } - - @Override - public void setConditionSubClassId(NodeId[] value) { - setProperty(ConditionType.CONDITION_SUB_CLASS_ID, value); - } - - @Override - public PropertyTypeNode getConditionSubClassNameNode() { - Optional propertyNode = getPropertyNode(ConditionType.CONDITION_SUB_CLASS_NAME); - return (PropertyTypeNode) propertyNode.orElse(null); - } - - @Override - public LocalizedText[] getConditionSubClassName() { - return getProperty(ConditionType.CONDITION_SUB_CLASS_NAME).orElse(null); - } - - @Override - public void setConditionSubClassName(LocalizedText[] value) { - setProperty(ConditionType.CONDITION_SUB_CLASS_NAME, value); - } - @Override public PropertyTypeNode getConditionNameNode() { Optional propertyNode = getPropertyNode(ConditionType.CONDITION_NAME); @@ -160,6 +128,22 @@ public void setRetain(Boolean value) { setProperty(ConditionType.RETAIN, value); } + @Override + public PropertyTypeNode getSupportsFilteredRetainNode() { + Optional propertyNode = getPropertyNode(ConditionType.SUPPORTS_FILTERED_RETAIN); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public Boolean getSupportsFilteredRetain() { + return getProperty(ConditionType.SUPPORTS_FILTERED_RETAIN).orElse(null); + } + + @Override + public void setSupportsFilteredRetain(Boolean value) { + setProperty(ConditionType.SUPPORTS_FILTERED_RETAIN, value); + } + @Override public PropertyTypeNode getClientUserIdNode() { Optional propertyNode = getPropertyNode(ConditionType.CLIENT_USER_ID); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DatagramDataSetReaderTransportType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DatagramDataSetReaderTransportType.java index 960078c8f..d9698bb2d 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DatagramDataSetReaderTransportType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DatagramDataSetReaderTransportType.java @@ -18,7 +18,7 @@ /** * @see https://reference.opcfoundation.org/v105/Core/docs/Part14/9.3.1/#9.3.1.4 */ -public interface DatagramDataSetReaderTransportType extends WriterGroupTransportType { +public interface DatagramDataSetReaderTransportType extends DataSetReaderTransportType { QualifiedProperty QOS_CATEGORY = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "QosCategory", diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DatagramDataSetReaderTransportTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DatagramDataSetReaderTransportTypeNode.java index 365b106b1..555b36259 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DatagramDataSetReaderTransportTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DatagramDataSetReaderTransportTypeNode.java @@ -25,7 +25,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.ReceiveQosDataType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; -public class DatagramDataSetReaderTransportTypeNode extends WriterGroupTransportTypeNode implements DatagramDataSetReaderTransportType { +public class DatagramDataSetReaderTransportTypeNode extends DataSetReaderTransportTypeNode implements DatagramDataSetReaderTransportType { public DatagramDataSetReaderTransportTypeNode(UaNodeContext context, NodeId nodeId, QualifiedName browseName, LocalizedText displayName, LocalizedText description, UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DiscrepancyAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DiscrepancyAlarmType.java index 748afd990..2d1b418c3 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DiscrepancyAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DiscrepancyAlarmType.java @@ -16,7 +16,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.25 */ public interface DiscrepancyAlarmType extends AlarmConditionType { QualifiedProperty TARGET_VALUE_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DiscreteAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DiscreteAlarmType.java index 64f58275a..fb0ad7ef4 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DiscreteAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/DiscreteAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.1 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.1 */ public interface DiscreteAlarmType extends AlarmConditionType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccApplicationCertificateType.java index 6d247a7bf..8a4d98542 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.6 */ public interface EccApplicationCertificateType extends ApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccBrainpoolP256r1ApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccBrainpoolP256r1ApplicationCertificateType.java index 88ff43204..9edf4934a 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccBrainpoolP256r1ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccBrainpoolP256r1ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.9 */ public interface EccBrainpoolP256r1ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccBrainpoolP384r1ApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccBrainpoolP384r1ApplicationCertificateType.java index 14fea1242..69401234a 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccBrainpoolP384r1ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccBrainpoolP384r1ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.10 */ public interface EccBrainpoolP384r1ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccCurve25519ApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccCurve25519ApplicationCertificateType.java index 088b1d537..bded72eec 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccCurve25519ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccCurve25519ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.11 */ public interface EccCurve25519ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccCurve448ApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccCurve448ApplicationCertificateType.java index 6190b7393..74a9e88c1 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccCurve448ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccCurve448ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.12 */ public interface EccCurve448ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccNistP256ApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccNistP256ApplicationCertificateType.java index d56e043f0..e7b7c409a 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccNistP256ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccNistP256ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.7 */ public interface EccNistP256ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccNistP384ApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccNistP384ApplicationCertificateType.java index 4f0ff36c0..9b964bbff 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccNistP384ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/EccNistP384ApplicationCertificateType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.8 */ public interface EccNistP384ApplicationCertificateType extends EccApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveDeviationAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveDeviationAlarmType.java index 1254bf2a5..69f3c504f 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveDeviationAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveDeviationAlarmType.java @@ -16,7 +16,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.21/#5.8.21.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.22/#5.8.22.3 */ public interface ExclusiveDeviationAlarmType extends ExclusiveLimitAlarmType { QualifiedProperty SETPOINT_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLevelAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLevelAlarmType.java index 4ef77dd28..155ebe489 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLevelAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLevelAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.20/#5.8.20.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.21/#5.8.21.3 */ public interface ExclusiveLevelAlarmType extends ExclusiveLimitAlarmType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLimitAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLimitAlarmType.java index 86dd00442..b6e03ce1f 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLimitAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLimitAlarmType.java @@ -14,7 +14,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.18/#5.8.18.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.19/#5.8.19.3 */ public interface ExclusiveLimitAlarmType extends LimitAlarmType { TwoStateVariableType getActiveStateNode(); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLimitStateMachineType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLimitStateMachineType.java index 41c3909fb..4b37bce26 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLimitStateMachineType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveLimitStateMachineType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.18/#5.8.18.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.19/#5.8.19.2 */ public interface ExclusiveLimitStateMachineType extends FiniteStateMachineType { StateType getHighHighNode(); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveRateOfChangeAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveRateOfChangeAlarmType.java index 194d0e6fc..551f03133 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveRateOfChangeAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExclusiveRateOfChangeAlarmType.java @@ -16,7 +16,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.EUInformation; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.22/#5.8.22.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.3 */ public interface ExclusiveRateOfChangeAlarmType extends ExclusiveLimitAlarmType { QualifiedProperty ENGINEERING_UNITS = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExtensionFieldsType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExtensionFieldsType.java index 6e6df6e68..adc246698 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExtensionFieldsType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ExtensionFieldsType.java @@ -48,7 +48,7 @@ public Argument[] getInputArguments() { return new Argument[]{ new Argument("FieldName", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=20").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("FieldValue", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=24").toNodeId(namespaceTable).orElseThrow(), -2, null, new LocalizedText("", "")) + new Argument("FieldValue", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=24").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) }; }); } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HistoricalDataConfigurationType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HistoricalDataConfigurationType.java index cfaac116d..8d0b16e7b 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HistoricalDataConfigurationType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HistoricalDataConfigurationType.java @@ -17,7 +17,7 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.ExceptionDeviationFormat; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.2.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.2.2 */ public interface HistoricalDataConfigurationType extends BaseObjectType { QualifiedProperty STEPPED = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HistoryServerCapabilitiesType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HistoryServerCapabilitiesType.java index fa796a636..f94b61e8f 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HistoryServerCapabilitiesType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HistoryServerCapabilitiesType.java @@ -16,7 +16,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Part11/5.4.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part11/5.4.2 */ public interface HistoryServerCapabilitiesType extends BaseObjectType { QualifiedProperty ACCESS_HISTORY_DATA_CAPABILITY = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HttpsCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HttpsCertificateType.java index 3f6a85def..5661e995b 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HttpsCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/HttpsCertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.3 + */ public interface HttpsCertificateType extends CertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/InstrumentDiagnosticAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/InstrumentDiagnosticAlarmType.java index 69816a95f..34d4590f4 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/InstrumentDiagnosticAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/InstrumentDiagnosticAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.5 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.5 */ public interface InstrumentDiagnosticAlarmType extends OffNormalAlarmType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialAuditEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialAuditEventType.java index f7623092a..ee1335220 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialAuditEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialAuditEventType.java @@ -14,6 +14,9 @@ import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyType; import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.5.8 + */ public interface KeyCredentialAuditEventType extends AuditUpdateMethodEventType { QualifiedProperty RESOURCE_URI = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialConfigurationFolderType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialConfigurationFolderType.java index d685f4881..db3ac9f95 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialConfigurationFolderType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialConfigurationFolderType.java @@ -24,6 +24,9 @@ import org.eclipse.milo.opcua.stack.core.types.structured.Argument; import org.eclipse.milo.opcua.stack.core.util.Lazy; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.6.1 + */ public interface KeyCredentialConfigurationFolderType extends FolderType { MethodNode getCreateCredentialMethodNode(); @@ -42,6 +45,7 @@ public Argument[] getInputArguments() { NamespaceTable namespaceTable = getNode().getNodeContext().getNamespaceTable(); return new Argument[]{ + new Argument("Name", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), new Argument("ResourceUri", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), new Argument("ProfileUri", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), new Argument("EndpointUrls", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), 1, new UInteger[]{UInteger.valueOf(0)}, new LocalizedText("", "")) @@ -63,16 +67,17 @@ public Argument[] getOutputArguments() { @Override protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext context, Variant[] inputValues) throws UaException { - String resourceUri = (String) inputValues[0].getValue(); - String profileUri = (String) inputValues[1].getValue(); - String[] endpointUrls = (String[]) inputValues[2].getValue(); + String name = (String) inputValues[0].getValue(); + String resourceUri = (String) inputValues[1].getValue(); + String profileUri = (String) inputValues[2].getValue(); + String[] endpointUrls = (String[]) inputValues[3].getValue(); Out credentialNodeId = new Out<>(); - invoke(context, resourceUri, profileUri, endpointUrls, credentialNodeId); + invoke(context, name, resourceUri, profileUri, endpointUrls, credentialNodeId); return new Variant[]{new Variant(credentialNodeId.get())}; } protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, - String resourceUri, String profileUri, String[] endpointUrls, Out credentialNodeId) - throws UaException; + String name, String resourceUri, String profileUri, String[] endpointUrls, + Out credentialNodeId) throws UaException; } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialConfigurationType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialConfigurationType.java index 6765339d1..11890d6e4 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialConfigurationType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialConfigurationType.java @@ -21,14 +21,13 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; import org.eclipse.milo.opcua.stack.core.types.structured.Argument; import org.eclipse.milo.opcua.stack.core.util.Lazy; /** - * @see https://reference.opcfoundation.org/v104/Core/docs/Amendment4/8.5.7 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.6.4 */ public interface KeyCredentialConfigurationType extends BaseObjectType { QualifiedProperty RESOURCE_URI = new QualifiedProperty<>( @@ -121,7 +120,7 @@ public Argument[] getOutputArguments() { return new Argument[]{ new Argument("PublicKey", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=15").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("RevisedSecurityPolicyUri", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) + new Argument("RevisedSecurityPolicyUri", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) }; }); } @@ -132,14 +131,14 @@ protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext con String credentialId = (String) inputValues[0].getValue(); String requestedSecurityPolicyUri = (String) inputValues[1].getValue(); Out publicKey = new Out<>(); - Out revisedSecurityPolicyUri = new Out<>(); + Out revisedSecurityPolicyUri = new Out<>(); invoke(context, credentialId, requestedSecurityPolicyUri, publicKey, revisedSecurityPolicyUri); return new Variant[]{new Variant(publicKey.get()), new Variant(revisedSecurityPolicyUri.get())}; } protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, String credentialId, String requestedSecurityPolicyUri, Out publicKey, - Out revisedSecurityPolicyUri) throws UaException; + Out revisedSecurityPolicyUri) throws UaException; } abstract class UpdateCredentialMethod extends AbstractMethodInvocationHandler { diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialDeletedAuditEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialDeletedAuditEventType.java index 55f337a6d..605549296 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialDeletedAuditEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialDeletedAuditEventType.java @@ -14,6 +14,9 @@ import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyType; import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.6.9 + */ public interface KeyCredentialDeletedAuditEventType extends KeyCredentialAuditEventType { QualifiedProperty RESOURCE_URI = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialUpdatedAuditEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialUpdatedAuditEventType.java index b611f4de1..a068a073d 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialUpdatedAuditEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/KeyCredentialUpdatedAuditEventType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/8.6.8 + */ public interface KeyCredentialUpdatedAuditEventType extends KeyCredentialAuditEventType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/LimitAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/LimitAlarmType.java index 3f36ca5d4..da8487664 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/LimitAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/LimitAlarmType.java @@ -16,7 +16,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.17 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.18 */ public interface LimitAlarmType extends AlarmConditionType { QualifiedProperty HIGH_HIGH_LIMIT = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveDeviationAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveDeviationAlarmType.java index ac3c3e843..936f5a695 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveDeviationAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveDeviationAlarmType.java @@ -16,7 +16,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.21/#5.8.21.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.22/#5.8.22.2 */ public interface NonExclusiveDeviationAlarmType extends NonExclusiveLimitAlarmType { QualifiedProperty SETPOINT_NODE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveLevelAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveLevelAlarmType.java index 66282e445..dbf9a646d 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveLevelAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveLevelAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.20/#5.8.20.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.21/#5.8.21.2 */ public interface NonExclusiveLevelAlarmType extends NonExclusiveLimitAlarmType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveLimitAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveLimitAlarmType.java index 88b0b6038..298882ea9 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveLimitAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveLimitAlarmType.java @@ -14,7 +14,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.19 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.20 */ public interface NonExclusiveLimitAlarmType extends LimitAlarmType { TwoStateVariableType getActiveStateNode(); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveRateOfChangeAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveRateOfChangeAlarmType.java index 1d5db5d6a..e232f4b6b 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveRateOfChangeAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/NonExclusiveRateOfChangeAlarmType.java @@ -16,7 +16,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.EUInformation; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.22/#5.8.22.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.2 */ public interface NonExclusiveRateOfChangeAlarmType extends NonExclusiveLimitAlarmType { QualifiedProperty ENGINEERING_UNITS = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/OffNormalAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/OffNormalAlarmType.java index b86b2fb72..9b9e537e9 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/OffNormalAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/OffNormalAlarmType.java @@ -16,7 +16,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.2 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.2 */ public interface OffNormalAlarmType extends DiscreteAlarmType { QualifiedProperty NORMAL_STATE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ProvisionableDeviceType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ProvisionableDeviceType.java new file mode 100644 index 000000000..b3a124412 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ProvisionableDeviceType.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.sdk.core.nodes.MethodNode; +import org.eclipse.milo.opcua.sdk.server.api.methods.AbstractMethodInvocationHandler; +import org.eclipse.milo.opcua.sdk.server.api.methods.Out; +import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyType; +import org.eclipse.milo.opcua.sdk.server.nodes.UaMethodNode; +import org.eclipse.milo.opcua.stack.core.NamespaceTable; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.Argument; +import org.eclipse.milo.opcua.stack.core.util.Lazy; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part21/9.3.3 + */ +public interface ProvisionableDeviceType extends BaseObjectType { + QualifiedProperty IS_SINGLETON = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "IsSingleton", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + + Boolean getIsSingleton(); + + void setIsSingleton(Boolean value); + + PropertyType getIsSingletonNode(); + + MethodNode getRequestTicketsMethodNode(); + + MethodNode getSetRegistrarEndpointsMethodNode(); + + abstract class RequestTicketsMethod extends AbstractMethodInvocationHandler { + private final Lazy outputArguments = new Lazy<>(); + + public RequestTicketsMethod(UaMethodNode node) { + super(node); + } + + @Override + public Argument[] getInputArguments() { + return new Argument[]{}; + } + + @Override + public Argument[] getOutputArguments() { + return outputArguments.getOrCompute(() -> { + NamespaceTable namespaceTable = getNode().getNodeContext().getNamespaceTable(); + + return new Argument[]{ + new Argument("Tickets", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=25726").toNodeId(namespaceTable).orElseThrow(), 1, new UInteger[]{UInteger.valueOf(0)}, new LocalizedText("", "")) + }; + }); + } + + @Override + protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext context, + Variant[] inputValues) throws UaException { + Out tickets = new Out<>(); + invoke(context, tickets); + return new Variant[]{new Variant(tickets.get())}; + } + + protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, + Out tickets) throws UaException; + } + + abstract class SetRegistrarEndpointsMethod extends AbstractMethodInvocationHandler { + private final Lazy inputArguments = new Lazy<>(); + + public SetRegistrarEndpointsMethod(UaMethodNode node) { + super(node); + } + + @Override + public Argument[] getInputArguments() { + return inputArguments.getOrCompute(() -> { + NamespaceTable namespaceTable = getNode().getNodeContext().getNamespaceTable(); + + return new Argument[]{ + new Argument("Registrars", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=308").toNodeId(namespaceTable).orElseThrow(), 1, new UInteger[]{UInteger.valueOf(0)}, new LocalizedText("", "")) + }; + }); + } + + @Override + public Argument[] getOutputArguments() { + return new Argument[]{}; + } + + @Override + protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext context, + Variant[] inputValues) throws UaException { + ApplicationDescription[] registrars = (ApplicationDescription[]) inputValues[0].getValue(); + invoke(context, registrars); + return new Variant[]{}; + } + + protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, + ApplicationDescription[] registrars) throws UaException; + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ProvisionableDeviceTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ProvisionableDeviceTypeNode.java new file mode 100644 index 000000000..0a9d20411 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ProvisionableDeviceTypeNode.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +import java.util.Optional; + +import org.eclipse.milo.opcua.sdk.core.Reference; +import org.eclipse.milo.opcua.sdk.core.nodes.VariableNode; +import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyTypeNode; +import org.eclipse.milo.opcua.sdk.server.nodes.UaMethodNode; +import org.eclipse.milo.opcua.sdk.server.nodes.UaNode; +import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class ProvisionableDeviceTypeNode extends BaseObjectTypeNode implements ProvisionableDeviceType { + public ProvisionableDeviceTypeNode(UaNodeContext context, NodeId nodeId, QualifiedName browseName, + LocalizedText displayName, LocalizedText description, UInteger writeMask, + UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } + + public ProvisionableDeviceTypeNode(UaNodeContext context, NodeId nodeId, QualifiedName browseName, + LocalizedText displayName, LocalizedText description, UInteger writeMask, + UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions); + } + + @Override + public PropertyTypeNode getIsSingletonNode() { + Optional propertyNode = getPropertyNode(ProvisionableDeviceType.IS_SINGLETON); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public Boolean getIsSingleton() { + return getProperty(ProvisionableDeviceType.IS_SINGLETON).orElse(null); + } + + @Override + public void setIsSingleton(Boolean value) { + setProperty(ProvisionableDeviceType.IS_SINGLETON, value); + } + + @Override + public UaMethodNode getRequestTicketsMethodNode() { + Optional methodNode = findNode("http://opcfoundation.org/UA/", "RequestTickets", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); + return (UaMethodNode) methodNode.orElse(null); + } + + @Override + public UaMethodNode getSetRegistrarEndpointsMethodNode() { + Optional methodNode = findNode("http://opcfoundation.org/UA/", "SetRegistrarEndpoints", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); + return (UaMethodNode) methodNode.orElse(null); + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubCapabilitiesType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubCapabilitiesType.java index fbab26c79..b023cbbfb 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubCapabilitiesType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubCapabilitiesType.java @@ -67,6 +67,46 @@ public interface PubSubCapabilitiesType extends BaseObjectType { UInteger.class ); + QualifiedProperty MAX_DATA_SET_WRITERS_PER_GROUP = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "MaxDataSetWritersPerGroup", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty MAX_NETWORK_MESSAGE_SIZE_DATAGRAM = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "MaxNetworkMessageSizeDatagram", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty MAX_NETWORK_MESSAGE_SIZE_BROKER = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "MaxNetworkMessageSizeBroker", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty SUPPORT_SECURITY_KEY_PULL = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "SupportSecurityKeyPull", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + + QualifiedProperty SUPPORT_SECURITY_KEY_PUSH = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "SupportSecurityKeyPush", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + UInteger getMaxPubSubConnections(); void setMaxPubSubConnections(UInteger value); @@ -102,4 +142,34 @@ public interface PubSubCapabilitiesType extends BaseObjectType { void setMaxFieldsPerDataSet(UInteger value); PropertyType getMaxFieldsPerDataSetNode(); + + UInteger getMaxDataSetWritersPerGroup(); + + void setMaxDataSetWritersPerGroup(UInteger value); + + PropertyType getMaxDataSetWritersPerGroupNode(); + + UInteger getMaxNetworkMessageSizeDatagram(); + + void setMaxNetworkMessageSizeDatagram(UInteger value); + + PropertyType getMaxNetworkMessageSizeDatagramNode(); + + UInteger getMaxNetworkMessageSizeBroker(); + + void setMaxNetworkMessageSizeBroker(UInteger value); + + PropertyType getMaxNetworkMessageSizeBrokerNode(); + + Boolean getSupportSecurityKeyPull(); + + void setSupportSecurityKeyPull(Boolean value); + + PropertyType getSupportSecurityKeyPullNode(); + + Boolean getSupportSecurityKeyPush(); + + void setSupportSecurityKeyPush(Boolean value); + + PropertyType getSupportSecurityKeyPushNode(); } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubCapabilitiesTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubCapabilitiesTypeNode.java index be74fe237..8bed403fc 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubCapabilitiesTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubCapabilitiesTypeNode.java @@ -134,4 +134,84 @@ public UInteger getMaxFieldsPerDataSet() { public void setMaxFieldsPerDataSet(UInteger value) { setProperty(PubSubCapabilitiesType.MAX_FIELDS_PER_DATA_SET, value); } + + @Override + public PropertyTypeNode getMaxDataSetWritersPerGroupNode() { + Optional propertyNode = getPropertyNode(PubSubCapabilitiesType.MAX_DATA_SET_WRITERS_PER_GROUP); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public UInteger getMaxDataSetWritersPerGroup() { + return getProperty(PubSubCapabilitiesType.MAX_DATA_SET_WRITERS_PER_GROUP).orElse(null); + } + + @Override + public void setMaxDataSetWritersPerGroup(UInteger value) { + setProperty(PubSubCapabilitiesType.MAX_DATA_SET_WRITERS_PER_GROUP, value); + } + + @Override + public PropertyTypeNode getMaxNetworkMessageSizeDatagramNode() { + Optional propertyNode = getPropertyNode(PubSubCapabilitiesType.MAX_NETWORK_MESSAGE_SIZE_DATAGRAM); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public UInteger getMaxNetworkMessageSizeDatagram() { + return getProperty(PubSubCapabilitiesType.MAX_NETWORK_MESSAGE_SIZE_DATAGRAM).orElse(null); + } + + @Override + public void setMaxNetworkMessageSizeDatagram(UInteger value) { + setProperty(PubSubCapabilitiesType.MAX_NETWORK_MESSAGE_SIZE_DATAGRAM, value); + } + + @Override + public PropertyTypeNode getMaxNetworkMessageSizeBrokerNode() { + Optional propertyNode = getPropertyNode(PubSubCapabilitiesType.MAX_NETWORK_MESSAGE_SIZE_BROKER); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public UInteger getMaxNetworkMessageSizeBroker() { + return getProperty(PubSubCapabilitiesType.MAX_NETWORK_MESSAGE_SIZE_BROKER).orElse(null); + } + + @Override + public void setMaxNetworkMessageSizeBroker(UInteger value) { + setProperty(PubSubCapabilitiesType.MAX_NETWORK_MESSAGE_SIZE_BROKER, value); + } + + @Override + public PropertyTypeNode getSupportSecurityKeyPullNode() { + Optional propertyNode = getPropertyNode(PubSubCapabilitiesType.SUPPORT_SECURITY_KEY_PULL); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public Boolean getSupportSecurityKeyPull() { + return getProperty(PubSubCapabilitiesType.SUPPORT_SECURITY_KEY_PULL).orElse(null); + } + + @Override + public void setSupportSecurityKeyPull(Boolean value) { + setProperty(PubSubCapabilitiesType.SUPPORT_SECURITY_KEY_PULL, value); + } + + @Override + public PropertyTypeNode getSupportSecurityKeyPushNode() { + Optional propertyNode = getPropertyNode(PubSubCapabilitiesType.SUPPORT_SECURITY_KEY_PUSH); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public Boolean getSupportSecurityKeyPush() { + return getProperty(PubSubCapabilitiesType.SUPPORT_SECURITY_KEY_PUSH).orElse(null); + } + + @Override + public void setSupportSecurityKeyPush(Boolean value) { + setProperty(PubSubCapabilitiesType.SUPPORT_SECURITY_KEY_PUSH, value); + } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubConfigurationType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubConfigurationType.java index 17cf54530..614de01ac 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubConfigurationType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PubSubConfigurationType.java @@ -65,8 +65,8 @@ public Argument[] getOutputArguments() { return new Argument[]{ new Argument("DefaultPublisherId", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=24").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("WriterGroupIds", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=5").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("DataSetWriterIds", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=5").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) + new Argument("WriterGroupIds", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=5").toNodeId(namespaceTable).orElseThrow(), 1, new UInteger[]{UInteger.valueOf(0)}, new LocalizedText("", "")), + new Argument("DataSetWriterIds", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=5").toNodeId(namespaceTable).orElseThrow(), 1, new UInteger[]{UInteger.valueOf(0)}, new LocalizedText("", "")) }; }); } @@ -78,16 +78,16 @@ protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext con UShort numReqWriterGroupIds = (UShort) inputValues[1].getValue(); UShort numReqDataSetWriterIds = (UShort) inputValues[2].getValue(); Out defaultPublisherId = new Out<>(); - Out writerGroupIds = new Out<>(); - Out dataSetWriterIds = new Out<>(); + Out writerGroupIds = new Out<>(); + Out dataSetWriterIds = new Out<>(); invoke(context, transportProfileUri, numReqWriterGroupIds, numReqDataSetWriterIds, defaultPublisherId, writerGroupIds, dataSetWriterIds); return new Variant[]{new Variant(defaultPublisherId.get()), new Variant(writerGroupIds.get()), new Variant(dataSetWriterIds.get())}; } protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, String transportProfileUri, UShort numReqWriterGroupIds, UShort numReqDataSetWriterIds, - Out defaultPublisherId, Out writerGroupIds, Out dataSetWriterIds) - throws UaException; + Out defaultPublisherId, Out writerGroupIds, + Out dataSetWriterIds) throws UaException; } abstract class CloseAndUpdateMethod extends AbstractMethodInvocationHandler { diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PublishSubscribeType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PublishSubscribeType.java index 409eaa99e..56efe52d2 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PublishSubscribeType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PublishSubscribeType.java @@ -26,6 +26,8 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.ULong; import org.eclipse.milo.opcua.stack.core.types.structured.Argument; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.KeyValuePair; import org.eclipse.milo.opcua.stack.core.types.structured.PubSubConnectionDataType; import org.eclipse.milo.opcua.stack.core.util.Lazy; @@ -57,6 +59,22 @@ public interface PublishSubscribeType extends PubSubKeyServiceType { UInteger.class ); + QualifiedProperty DEFAULT_SECURITY_KEY_SERVICES = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "DefaultSecurityKeyServices", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=312"), + 1, + EndpointDescription[].class + ); + + QualifiedProperty CONFIGURATION_PROPERTIES = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ConfigurationProperties", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=14533"), + 1, + KeyValuePair[].class + ); + String[] getSupportedTransportProfiles(); void setSupportedTransportProfiles(String[] value); @@ -75,6 +93,18 @@ public interface PublishSubscribeType extends PubSubKeyServiceType { PropertyType getConfigurationVersionNode(); + EndpointDescription[] getDefaultSecurityKeyServices(); + + void setDefaultSecurityKeyServices(EndpointDescription[] value); + + PropertyType getDefaultSecurityKeyServicesNode(); + + KeyValuePair[] getConfigurationProperties(); + + void setConfigurationProperties(KeyValuePair[] value); + + PropertyType getConfigurationPropertiesNode(); + MethodNode getSetSecurityKeysMethodNode(); MethodNode getAddConnectionMethodNode(); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PublishSubscribeTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PublishSubscribeTypeNode.java index 6923bb840..ed27c7e7b 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PublishSubscribeTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/PublishSubscribeTypeNode.java @@ -26,6 +26,8 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.ULong; import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.KeyValuePair; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; public class PublishSubscribeTypeNode extends PubSubKeyServiceTypeNode implements PublishSubscribeType { @@ -92,6 +94,38 @@ public void setConfigurationVersion(UInteger value) { setProperty(PublishSubscribeType.CONFIGURATION_VERSION, value); } + @Override + public PropertyTypeNode getDefaultSecurityKeyServicesNode() { + Optional propertyNode = getPropertyNode(PublishSubscribeType.DEFAULT_SECURITY_KEY_SERVICES); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public EndpointDescription[] getDefaultSecurityKeyServices() { + return getProperty(PublishSubscribeType.DEFAULT_SECURITY_KEY_SERVICES).orElse(null); + } + + @Override + public void setDefaultSecurityKeyServices(EndpointDescription[] value) { + setProperty(PublishSubscribeType.DEFAULT_SECURITY_KEY_SERVICES, value); + } + + @Override + public PropertyTypeNode getConfigurationPropertiesNode() { + Optional propertyNode = getPropertyNode(PublishSubscribeType.CONFIGURATION_PROPERTIES); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public KeyValuePair[] getConfigurationProperties() { + return getProperty(PublishSubscribeType.CONFIGURATION_PROPERTIES).orElse(null); + } + + @Override + public void setConfigurationProperties(KeyValuePair[] value) { + setProperty(PublishSubscribeType.CONFIGURATION_PROPERTIES, value); + } + @Override public UaMethodNode getSetSecurityKeysMethodNode() { Optional methodNode = findNode("http://opcfoundation.org/UA/", "SetSecurityKeys", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/RsaMinApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/RsaMinApplicationCertificateType.java index ac792c13f..9cad093c2 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/RsaMinApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/RsaMinApplicationCertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.4 + */ public interface RsaMinApplicationCertificateType extends ApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/RsaSha256ApplicationCertificateType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/RsaSha256ApplicationCertificateType.java index 9ee44ad1d..a26c87f3a 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/RsaSha256ApplicationCertificateType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/RsaSha256ApplicationCertificateType.java @@ -10,5 +10,8 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.4/#7.8.4.5 + */ public interface RsaSha256ApplicationCertificateType extends ApplicationCertificateType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerCapabilitiesType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerCapabilitiesType.java index 9d64068d4..5f271d946 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerCapabilitiesType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerCapabilitiesType.java @@ -158,6 +158,14 @@ public interface ServerCapabilitiesType extends BaseObjectType { UInteger.class ); + QualifiedProperty MAX_MONITORED_ITEMS_QUEUE_SIZE = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "MaxMonitoredItemsQueueSize", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + QualifiedProperty CONFORMANCE_UNITS = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "ConformanceUnits", @@ -268,6 +276,12 @@ public interface ServerCapabilitiesType extends BaseObjectType { PropertyType getMaxWhereClauseParametersNode(); + UInteger getMaxMonitoredItemsQueueSize(); + + void setMaxMonitoredItemsQueueSize(UInteger value); + + PropertyType getMaxMonitoredItemsQueueSizeNode(); + QualifiedName[] getConformanceUnits(); void setConformanceUnits(QualifiedName[] value); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerCapabilitiesTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerCapabilitiesTypeNode.java index 46ba8f247..6b7ed5bac 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerCapabilitiesTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerCapabilitiesTypeNode.java @@ -314,6 +314,22 @@ public void setMaxWhereClauseParameters(UInteger value) { setProperty(ServerCapabilitiesType.MAX_WHERE_CLAUSE_PARAMETERS, value); } + @Override + public PropertyTypeNode getMaxMonitoredItemsQueueSizeNode() { + Optional propertyNode = getPropertyNode(ServerCapabilitiesType.MAX_MONITORED_ITEMS_QUEUE_SIZE); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public UInteger getMaxMonitoredItemsQueueSize() { + return getProperty(ServerCapabilitiesType.MAX_MONITORED_ITEMS_QUEUE_SIZE).orElse(null); + } + + @Override + public void setMaxMonitoredItemsQueueSize(UInteger value) { + setProperty(ServerCapabilitiesType.MAX_MONITORED_ITEMS_QUEUE_SIZE, value); + } + @Override public PropertyTypeNode getConformanceUnitsNode() { Optional propertyNode = getPropertyNode(ServerCapabilitiesType.CONFORMANCE_UNITS); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerConfigurationType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerConfigurationType.java index 0d61a0697..d6c10ba46 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerConfigurationType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerConfigurationType.java @@ -24,10 +24,38 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; import org.eclipse.milo.opcua.stack.core.types.structured.Argument; import org.eclipse.milo.opcua.stack.core.util.Lazy; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.10.3 + */ public interface ServerConfigurationType extends BaseObjectType { + QualifiedProperty APPLICATION_URI = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ApplicationUri", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23751"), + -1, + String.class + ); + + QualifiedProperty PRODUCT_URI = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ProductUri", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23751"), + -1, + String.class + ); + + QualifiedProperty APPLICATION_TYPE = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ApplicationType", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=307"), + -1, + ApplicationType.class + ); + QualifiedProperty SERVER_CAPABILITIES = new QualifiedProperty<>( "http://opcfoundation.org/UA/", "ServerCapabilities", @@ -60,6 +88,32 @@ public interface ServerConfigurationType extends BaseObjectType { Boolean.class ); + QualifiedProperty HAS_SECURE_ELEMENT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "HasSecureElement", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1"), + -1, + Boolean.class + ); + + String getApplicationUri(); + + void setApplicationUri(String value); + + PropertyType getApplicationUriNode(); + + String getProductUri(); + + void setProductUri(String value); + + PropertyType getProductUriNode(); + + ApplicationType getApplicationType(); + + void setApplicationType(ApplicationType value); + + PropertyType getApplicationTypeNode(); + String[] getServerCapabilities(); void setServerCapabilities(String[] value); @@ -84,16 +138,30 @@ public interface ServerConfigurationType extends BaseObjectType { PropertyType getMulticastDnsEnabledNode(); + Boolean getHasSecureElement(); + + void setHasSecureElement(Boolean value); + + PropertyType getHasSecureElementNode(); + CertificateGroupFolderType getCertificateGroupsNode(); MethodNode getUpdateCertificateMethodNode(); + MethodNode getGetCertificatesMethodNode(); + MethodNode getApplyChangesMethodNode(); + MethodNode getCancelChangesMethodNode(); + MethodNode getCreateSigningRequestMethodNode(); MethodNode getGetRejectedListMethodNode(); + MethodNode getResetToServerDefaultsMethodNode(); + + TransactionDiagnosticsType getTransactionDiagnosticsNode(); + abstract class UpdateCertificateMethod extends AbstractMethodInvocationHandler { private final Lazy inputArguments = new Lazy<>(); @@ -150,6 +218,53 @@ protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext Out applyChangesRequired) throws UaException; } + abstract class GetCertificatesMethod extends AbstractMethodInvocationHandler { + private final Lazy inputArguments = new Lazy<>(); + + private final Lazy outputArguments = new Lazy<>(); + + public GetCertificatesMethod(UaMethodNode node) { + super(node); + } + + @Override + public Argument[] getInputArguments() { + return inputArguments.getOrCompute(() -> { + NamespaceTable namespaceTable = getNode().getNodeContext().getNamespaceTable(); + + return new Argument[]{ + new Argument("CertificateGroupId", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) + }; + }); + } + + @Override + public Argument[] getOutputArguments() { + return outputArguments.getOrCompute(() -> { + NamespaceTable namespaceTable = getNode().getNodeContext().getNamespaceTable(); + + return new Argument[]{ + new Argument("CertificateTypeIds", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17").toNodeId(namespaceTable).orElseThrow(), 1, new UInteger[]{UInteger.valueOf(0)}, new LocalizedText("", "")), + new Argument("Certificates", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=15").toNodeId(namespaceTable).orElseThrow(), 1, new UInteger[]{UInteger.valueOf(0)}, new LocalizedText("", "")) + }; + }); + } + + @Override + protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext context, + Variant[] inputValues) throws UaException { + NodeId certificateGroupId = (NodeId) inputValues[0].getValue(); + Out certificateTypeIds = new Out<>(); + Out certificates = new Out<>(); + invoke(context, certificateGroupId, certificateTypeIds, certificates); + return new Variant[]{new Variant(certificateTypeIds.get()), new Variant(certificates.get())}; + } + + protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, + NodeId certificateGroupId, Out certificateTypeIds, Out certificates) + throws UaException; + } + abstract class ApplyChangesMethod extends AbstractMethodInvocationHandler { public ApplyChangesMethod(UaMethodNode node) { super(node); @@ -176,6 +291,32 @@ protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext UaException; } + abstract class CancelChangesMethod extends AbstractMethodInvocationHandler { + public CancelChangesMethod(UaMethodNode node) { + super(node); + } + + @Override + public Argument[] getInputArguments() { + return new Argument[]{}; + } + + @Override + public Argument[] getOutputArguments() { + return new Argument[]{}; + } + + @Override + protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext context, + Variant[] inputValues) throws UaException { + invoke(context); + return new Variant[]{}; + } + + protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context) throws + UaException; + } + abstract class CreateSigningRequestMethod extends AbstractMethodInvocationHandler { private final Lazy inputArguments = new Lazy<>(); @@ -264,4 +405,30 @@ protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext con protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, Out certificates) throws UaException; } + + abstract class ResetToServerDefaultsMethod extends AbstractMethodInvocationHandler { + public ResetToServerDefaultsMethod(UaMethodNode node) { + super(node); + } + + @Override + public Argument[] getInputArguments() { + return new Argument[]{}; + } + + @Override + public Argument[] getOutputArguments() { + return new Argument[]{}; + } + + @Override + protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext context, + Variant[] inputValues) throws UaException { + invoke(context); + return new Variant[]{}; + } + + protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context) throws + UaException; + } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerConfigurationTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerConfigurationTypeNode.java index 1aaf0662b..edbc0a602 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerConfigurationTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ServerConfigurationTypeNode.java @@ -24,6 +24,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; @@ -43,6 +44,54 @@ public ServerConfigurationTypeNode(UaNodeContext context, NodeId nodeId, Qualifi super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions); } + @Override + public PropertyTypeNode getApplicationUriNode() { + Optional propertyNode = getPropertyNode(ServerConfigurationType.APPLICATION_URI); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public String getApplicationUri() { + return getProperty(ServerConfigurationType.APPLICATION_URI).orElse(null); + } + + @Override + public void setApplicationUri(String value) { + setProperty(ServerConfigurationType.APPLICATION_URI, value); + } + + @Override + public PropertyTypeNode getProductUriNode() { + Optional propertyNode = getPropertyNode(ServerConfigurationType.PRODUCT_URI); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public String getProductUri() { + return getProperty(ServerConfigurationType.PRODUCT_URI).orElse(null); + } + + @Override + public void setProductUri(String value) { + setProperty(ServerConfigurationType.PRODUCT_URI, value); + } + + @Override + public PropertyTypeNode getApplicationTypeNode() { + Optional propertyNode = getPropertyNode(ServerConfigurationType.APPLICATION_TYPE); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public ApplicationType getApplicationType() { + return getProperty(ServerConfigurationType.APPLICATION_TYPE).orElse(null); + } + + @Override + public void setApplicationType(ApplicationType value) { + setProperty(ServerConfigurationType.APPLICATION_TYPE, value); + } + @Override public PropertyTypeNode getServerCapabilitiesNode() { Optional propertyNode = getPropertyNode(ServerConfigurationType.SERVER_CAPABILITIES); @@ -107,6 +156,22 @@ public void setMulticastDnsEnabled(Boolean value) { setProperty(ServerConfigurationType.MULTICAST_DNS_ENABLED, value); } + @Override + public PropertyTypeNode getHasSecureElementNode() { + Optional propertyNode = getPropertyNode(ServerConfigurationType.HAS_SECURE_ELEMENT); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public Boolean getHasSecureElement() { + return getProperty(ServerConfigurationType.HAS_SECURE_ELEMENT).orElse(null); + } + + @Override + public void setHasSecureElement(Boolean value) { + setProperty(ServerConfigurationType.HAS_SECURE_ELEMENT, value); + } + @Override public CertificateGroupFolderTypeNode getCertificateGroupsNode() { Optional component = getObjectComponent("http://opcfoundation.org/UA/", "CertificateGroups"); @@ -119,12 +184,24 @@ public UaMethodNode getUpdateCertificateMethodNode() { return (UaMethodNode) methodNode.orElse(null); } + @Override + public UaMethodNode getGetCertificatesMethodNode() { + Optional methodNode = findNode("http://opcfoundation.org/UA/", "GetCertificates", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); + return (UaMethodNode) methodNode.orElse(null); + } + @Override public UaMethodNode getApplyChangesMethodNode() { Optional methodNode = findNode("http://opcfoundation.org/UA/", "ApplyChanges", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); return (UaMethodNode) methodNode.orElse(null); } + @Override + public UaMethodNode getCancelChangesMethodNode() { + Optional methodNode = findNode("http://opcfoundation.org/UA/", "CancelChanges", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); + return (UaMethodNode) methodNode.orElse(null); + } + @Override public UaMethodNode getCreateSigningRequestMethodNode() { Optional methodNode = findNode("http://opcfoundation.org/UA/", "CreateSigningRequest", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); @@ -136,4 +213,16 @@ public UaMethodNode getGetRejectedListMethodNode() { Optional methodNode = findNode("http://opcfoundation.org/UA/", "GetRejectedList", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); return (UaMethodNode) methodNode.orElse(null); } + + @Override + public UaMethodNode getResetToServerDefaultsMethodNode() { + Optional methodNode = findNode("http://opcfoundation.org/UA/", "ResetToServerDefaults", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); + return (UaMethodNode) methodNode.orElse(null); + } + + @Override + public TransactionDiagnosticsTypeNode getTransactionDiagnosticsNode() { + Optional component = getObjectComponent("http://opcfoundation.org/UA/", "TransactionDiagnostics"); + return (TransactionDiagnosticsTypeNode) component.orElse(null); + } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ShelvedStateMachineType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ShelvedStateMachineType.java index e96501e0e..fb952afd8 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ShelvedStateMachineType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/ShelvedStateMachineType.java @@ -24,7 +24,7 @@ import org.eclipse.milo.opcua.stack.core.util.Lazy; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.16/#5.8.16.1 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.17/#5.8.17.1 */ public interface ShelvedStateMachineType extends FiniteStateMachineType { QualifiedProperty UNSHELVE_TIME = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/SystemDiagnosticAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/SystemDiagnosticAlarmType.java index f37fba59f..04f9612ae 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/SystemDiagnosticAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/SystemDiagnosticAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.6 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.6 */ public interface SystemDiagnosticAlarmType extends OffNormalAlarmType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/SystemOffNormalAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/SystemOffNormalAlarmType.java index 077579c6a..566dae6a7 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/SystemOffNormalAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/SystemOffNormalAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.3 */ public interface SystemOffNormalAlarmType extends OffNormalAlarmType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TransactionDiagnosticsType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TransactionDiagnosticsType.java new file mode 100644 index 000000000..73cee7314 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TransactionDiagnosticsType.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyType; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.structured.TransactionErrorType; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.10.11 + */ +public interface TransactionDiagnosticsType extends BaseObjectType { + QualifiedProperty START_TIME = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "StartTime", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=294"), + -1, + DateTime.class + ); + + QualifiedProperty END_TIME = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "EndTime", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=294"), + -1, + DateTime.class + ); + + QualifiedProperty RESULT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "Result", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=19"), + -1, + StatusCode.class + ); + + QualifiedProperty AFFECTED_TRUST_LISTS = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "AffectedTrustLists", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + 1, + NodeId[].class + ); + + QualifiedProperty AFFECTED_CERTIFICATE_GROUPS = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "AffectedCertificateGroups", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + 1, + NodeId[].class + ); + + QualifiedProperty ERRORS = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "Errors", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=32285"), + 1, + TransactionErrorType[].class + ); + + DateTime getStartTime(); + + void setStartTime(DateTime value); + + PropertyType getStartTimeNode(); + + DateTime getEndTime(); + + void setEndTime(DateTime value); + + PropertyType getEndTimeNode(); + + StatusCode getResult(); + + void setResult(StatusCode value); + + PropertyType getResultNode(); + + NodeId[] getAffectedTrustLists(); + + void setAffectedTrustLists(NodeId[] value); + + PropertyType getAffectedTrustListsNode(); + + NodeId[] getAffectedCertificateGroups(); + + void setAffectedCertificateGroups(NodeId[] value); + + PropertyType getAffectedCertificateGroupsNode(); + + TransactionErrorType[] getErrors(); + + void setErrors(TransactionErrorType[] value); + + PropertyType getErrorsNode(); +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TransactionDiagnosticsTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TransactionDiagnosticsTypeNode.java new file mode 100644 index 000000000..cc21c407d --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TransactionDiagnosticsTypeNode.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +import java.util.Optional; + +import org.eclipse.milo.opcua.sdk.core.nodes.VariableNode; +import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyTypeNode; +import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; +import org.eclipse.milo.opcua.stack.core.types.structured.TransactionErrorType; + +public class TransactionDiagnosticsTypeNode extends BaseObjectTypeNode implements TransactionDiagnosticsType { + public TransactionDiagnosticsTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } + + public TransactionDiagnosticsTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions); + } + + @Override + public PropertyTypeNode getStartTimeNode() { + Optional propertyNode = getPropertyNode(TransactionDiagnosticsType.START_TIME); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public DateTime getStartTime() { + return getProperty(TransactionDiagnosticsType.START_TIME).orElse(null); + } + + @Override + public void setStartTime(DateTime value) { + setProperty(TransactionDiagnosticsType.START_TIME, value); + } + + @Override + public PropertyTypeNode getEndTimeNode() { + Optional propertyNode = getPropertyNode(TransactionDiagnosticsType.END_TIME); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public DateTime getEndTime() { + return getProperty(TransactionDiagnosticsType.END_TIME).orElse(null); + } + + @Override + public void setEndTime(DateTime value) { + setProperty(TransactionDiagnosticsType.END_TIME, value); + } + + @Override + public PropertyTypeNode getResultNode() { + Optional propertyNode = getPropertyNode(TransactionDiagnosticsType.RESULT); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public StatusCode getResult() { + return getProperty(TransactionDiagnosticsType.RESULT).orElse(null); + } + + @Override + public void setResult(StatusCode value) { + setProperty(TransactionDiagnosticsType.RESULT, value); + } + + @Override + public PropertyTypeNode getAffectedTrustListsNode() { + Optional propertyNode = getPropertyNode(TransactionDiagnosticsType.AFFECTED_TRUST_LISTS); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public NodeId[] getAffectedTrustLists() { + return getProperty(TransactionDiagnosticsType.AFFECTED_TRUST_LISTS).orElse(null); + } + + @Override + public void setAffectedTrustLists(NodeId[] value) { + setProperty(TransactionDiagnosticsType.AFFECTED_TRUST_LISTS, value); + } + + @Override + public PropertyTypeNode getAffectedCertificateGroupsNode() { + Optional propertyNode = getPropertyNode(TransactionDiagnosticsType.AFFECTED_CERTIFICATE_GROUPS); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public NodeId[] getAffectedCertificateGroups() { + return getProperty(TransactionDiagnosticsType.AFFECTED_CERTIFICATE_GROUPS).orElse(null); + } + + @Override + public void setAffectedCertificateGroups(NodeId[] value) { + setProperty(TransactionDiagnosticsType.AFFECTED_CERTIFICATE_GROUPS, value); + } + + @Override + public PropertyTypeNode getErrorsNode() { + Optional propertyNode = getPropertyNode(TransactionDiagnosticsType.ERRORS); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public TransactionErrorType[] getErrors() { + return getProperty(TransactionDiagnosticsType.ERRORS).orElse(null); + } + + @Override + public void setErrors(TransactionErrorType[] value) { + setProperty(TransactionDiagnosticsType.ERRORS, value); + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TripAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TripAlarmType.java index 8d696da86..049c9eeda 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TripAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TripAlarmType.java @@ -11,7 +11,7 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.23/#5.8.23.4 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/5.8.24/#5.8.24.4 */ public interface TripAlarmType extends OffNormalAlarmType { } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListOutOfDateAlarmType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListOutOfDateAlarmType.java index 08ecb9e6a..a02f82144 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListOutOfDateAlarmType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListOutOfDateAlarmType.java @@ -16,6 +16,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.2/#7.8.2.9 + */ public interface TrustListOutOfDateAlarmType extends SystemOffNormalAlarmType { QualifiedProperty TRUST_LIST_ID = new QualifiedProperty<>( "http://opcfoundation.org/UA/", diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListType.java index 8bccc1e2b..90c08d4eb 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListType.java @@ -25,8 +25,12 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.structured.Argument; +import org.eclipse.milo.opcua.stack.core.types.structured.TrustListValidationOptions; import org.eclipse.milo.opcua.stack.core.util.Lazy; +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.2/#7.8.2.1 + */ public interface TrustListType extends FileType { QualifiedProperty LAST_UPDATE_TIME = new QualifiedProperty<>( "http://opcfoundation.org/UA/", @@ -44,6 +48,22 @@ public interface TrustListType extends FileType { Double.class ); + QualifiedProperty ACTIVITY_TIMEOUT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ActivityTimeout", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=290"), + -1, + Double.class + ); + + QualifiedProperty DEFAULT_VALIDATION_OPTIONS = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "DefaultValidationOptions", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=23564"), + -1, + TrustListValidationOptions.class + ); + DateTime getLastUpdateTime(); void setLastUpdateTime(DateTime value); @@ -56,6 +76,18 @@ public interface TrustListType extends FileType { PropertyType getUpdateFrequencyNode(); + Double getActivityTimeout(); + + void setActivityTimeout(Double value); + + PropertyType getActivityTimeoutNode(); + + TrustListValidationOptions getDefaultValidationOptions(); + + void setDefaultValidationOptions(TrustListValidationOptions value); + + PropertyType getDefaultValidationOptionsNode(); + MethodNode getOpenWithMasksMethodNode(); MethodNode getCloseAndUpdateMethodNode(); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListTypeNode.java index 729961b60..56df6ef31 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListTypeNode.java @@ -26,6 +26,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; +import org.eclipse.milo.opcua.stack.core.types.structured.TrustListValidationOptions; public class TrustListTypeNode extends FileTypeNode implements TrustListType { public TrustListTypeNode(UaNodeContext context, NodeId nodeId, QualifiedName browseName, @@ -75,6 +76,38 @@ public void setUpdateFrequency(Double value) { setProperty(TrustListType.UPDATE_FREQUENCY, value); } + @Override + public PropertyTypeNode getActivityTimeoutNode() { + Optional propertyNode = getPropertyNode(TrustListType.ACTIVITY_TIMEOUT); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public Double getActivityTimeout() { + return getProperty(TrustListType.ACTIVITY_TIMEOUT).orElse(null); + } + + @Override + public void setActivityTimeout(Double value) { + setProperty(TrustListType.ACTIVITY_TIMEOUT, value); + } + + @Override + public PropertyTypeNode getDefaultValidationOptionsNode() { + Optional propertyNode = getPropertyNode(TrustListType.DEFAULT_VALIDATION_OPTIONS); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public TrustListValidationOptions getDefaultValidationOptions() { + return getProperty(TrustListType.DEFAULT_VALIDATION_OPTIONS).orElse(null); + } + + @Override + public void setDefaultValidationOptions(TrustListValidationOptions value) { + setProperty(TrustListType.DEFAULT_VALIDATION_OPTIONS, value); + } + @Override public UaMethodNode getOpenWithMasksMethodNode() { Optional methodNode = findNode("http://opcfoundation.org/UA/", "OpenWithMasks", node -> node instanceof UaMethodNode, Reference.HAS_COMPONENT_PREDICATE); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdateRequestedAuditEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdateRequestedAuditEventType.java new file mode 100644 index 000000000..624c9255e --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdateRequestedAuditEventType.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.2/#7.8.2.10 + */ +public interface TrustListUpdateRequestedAuditEventType extends AuditUpdateMethodEventType { +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdateRequestedAuditEventTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdateRequestedAuditEventTypeNode.java new file mode 100644 index 000000000..42bef12eb --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdateRequestedAuditEventTypeNode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.objects; + +import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class TrustListUpdateRequestedAuditEventTypeNode extends AuditUpdateMethodEventTypeNode implements TrustListUpdateRequestedAuditEventType { + public TrustListUpdateRequestedAuditEventTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + UByte eventNotifier) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, eventNotifier); + } + + public TrustListUpdateRequestedAuditEventTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions); + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdatedAuditEventType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdatedAuditEventType.java index e08e319aa..203e37a7e 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdatedAuditEventType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdatedAuditEventType.java @@ -10,5 +10,26 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; -public interface TrustListUpdatedAuditEventType extends AuditUpdateMethodEventType { +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyType; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.2/#7.8.2.11 + */ +public interface TrustListUpdatedAuditEventType extends AuditEventType { + QualifiedProperty TRUST_LIST_ID = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "TrustListId", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=17"), + -1, + NodeId.class + ); + + NodeId getTrustListId(); + + void setTrustListId(NodeId value); + + PropertyType getTrustListIdNode(); } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdatedAuditEventTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdatedAuditEventTypeNode.java index cf73da203..9a015f7d2 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdatedAuditEventTypeNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/TrustListUpdatedAuditEventTypeNode.java @@ -10,6 +10,10 @@ package org.eclipse.milo.opcua.sdk.server.model.objects; +import java.util.Optional; + +import org.eclipse.milo.opcua.sdk.core.nodes.VariableNode; +import org.eclipse.milo.opcua.sdk.server.model.variables.PropertyTypeNode; import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; @@ -19,7 +23,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; -public class TrustListUpdatedAuditEventTypeNode extends AuditUpdateMethodEventTypeNode implements TrustListUpdatedAuditEventType { +public class TrustListUpdatedAuditEventTypeNode extends AuditEventTypeNode implements TrustListUpdatedAuditEventType { public TrustListUpdatedAuditEventTypeNode(UaNodeContext context, NodeId nodeId, QualifiedName browseName, LocalizedText displayName, LocalizedText description, UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, @@ -34,4 +38,20 @@ public TrustListUpdatedAuditEventTypeNode(UaNodeContext context, NodeId nodeId, RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions) { super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions); } + + @Override + public PropertyTypeNode getTrustListIdNode() { + Optional propertyNode = getPropertyNode(TrustListUpdatedAuditEventType.TRUST_LIST_ID); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public NodeId getTrustListId() { + return getProperty(TrustListUpdatedAuditEventType.TRUST_LIST_ID).orElse(null); + } + + @Override + public void setTrustListId(NodeId value) { + setProperty(TrustListUpdatedAuditEventType.TRUST_LIST_ID, value); + } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/UserManagementType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/UserManagementType.java index 2284dbe8f..b036d2ead 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/UserManagementType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/objects/UserManagementType.java @@ -151,8 +151,11 @@ public Argument[] getInputArguments() { return new Argument[]{ new Argument("UserName", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), + new Argument("ModifyPassword", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), new Argument("Password", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), + new Argument("ModifyUserConfiguration", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), new Argument("UserConfiguration", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=24279").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), + new Argument("ModifyDescription", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=1").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), new Argument("Description", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) }; }); @@ -167,16 +170,20 @@ public Argument[] getOutputArguments() { protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext context, Variant[] inputValues) throws UaException { String userName = (String) inputValues[0].getValue(); - String password = (String) inputValues[1].getValue(); - UserConfigurationMask userConfiguration = (UserConfigurationMask) inputValues[2].getValue(); - String description = (String) inputValues[3].getValue(); - invoke(context, userName, password, userConfiguration, description); + Boolean modifyPassword = (Boolean) inputValues[1].getValue(); + String password = (String) inputValues[2].getValue(); + Boolean modifyUserConfiguration = (Boolean) inputValues[3].getValue(); + UserConfigurationMask userConfiguration = (UserConfigurationMask) inputValues[4].getValue(); + Boolean modifyDescription = (Boolean) inputValues[5].getValue(); + String description = (String) inputValues[6].getValue(); + invoke(context, userName, modifyPassword, password, modifyUserConfiguration, userConfiguration, modifyDescription, description); return new Variant[]{}; } protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, - String userName, String password, UserConfigurationMask userConfiguration, - String description) throws UaException; + String userName, Boolean modifyPassword, String password, Boolean modifyUserConfiguration, + UserConfigurationMask userConfiguration, Boolean modifyDescription, String description) + throws UaException; } abstract class RemoveUserMethod extends AbstractMethodInvocationHandler { @@ -192,10 +199,7 @@ public Argument[] getInputArguments() { NamespaceTable namespaceTable = getNode().getNodeContext().getNamespaceTable(); return new Argument[]{ - new Argument("UserName", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("Password", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("UserConfiguration", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=24279").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("Description", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) + new Argument("UserName", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) }; }); } @@ -209,16 +213,12 @@ public Argument[] getOutputArguments() { protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext context, Variant[] inputValues) throws UaException { String userName = (String) inputValues[0].getValue(); - String password = (String) inputValues[1].getValue(); - UserConfigurationMask userConfiguration = (UserConfigurationMask) inputValues[2].getValue(); - String description = (String) inputValues[3].getValue(); - invoke(context, userName, password, userConfiguration, description); + invoke(context, userName); return new Variant[]{}; } protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, - String userName, String password, UserConfigurationMask userConfiguration, - String description) throws UaException; + String userName) throws UaException; } abstract class ChangePasswordMethod extends AbstractMethodInvocationHandler { @@ -234,10 +234,8 @@ public Argument[] getInputArguments() { NamespaceTable namespaceTable = getNode().getNodeContext().getNamespaceTable(); return new Argument[]{ - new Argument("UserName", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("Password", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("UserConfiguration", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=24279").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), - new Argument("Description", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) + new Argument("OldPassword", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")), + new Argument("NewPassword", ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=12").toNodeId(namespaceTable).orElseThrow(), -1, null, new LocalizedText("", "")) }; }); } @@ -250,16 +248,13 @@ public Argument[] getOutputArguments() { @Override protected Variant[] invoke(AbstractMethodInvocationHandler.InvocationContext context, Variant[] inputValues) throws UaException { - String userName = (String) inputValues[0].getValue(); - String password = (String) inputValues[1].getValue(); - UserConfigurationMask userConfiguration = (UserConfigurationMask) inputValues[2].getValue(); - String description = (String) inputValues[3].getValue(); - invoke(context, userName, password, userConfiguration, description); + String oldPassword = (String) inputValues[0].getValue(); + String newPassword = (String) inputValues[1].getValue(); + invoke(context, oldPassword, newPassword); return new Variant[]{}; } protected abstract void invoke(AbstractMethodInvocationHandler.InvocationContext context, - String userName, String password, UserConfigurationMask userConfiguration, - String description) throws UaException; + String oldPassword, String newPassword) throws UaException; } } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmRateVariableType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmRateVariableType.java index 19f42c5f4..232fc81a8 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmRateVariableType.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmRateVariableType.java @@ -15,7 +15,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; /** - * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/8.3 + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/9.3 */ public interface AlarmRateVariableType extends BaseDataVariableType { QualifiedProperty RATE = new QualifiedProperty<>( diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmStateVariableType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmStateVariableType.java new file mode 100644 index 000000000..689d8a8e5 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmStateVariableType.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.variables; + +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; +import org.eclipse.milo.opcua.stack.core.types.structured.ContentFilter; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/8.2 + */ +public interface AlarmStateVariableType extends BaseDataVariableType { + QualifiedProperty HIGHEST_ACTIVE_SEVERITY = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "HighestActiveSeverity", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=5"), + -1, + UShort.class + ); + + QualifiedProperty HIGHEST_UNACK_SEVERITY = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "HighestUnackSeverity", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=5"), + -1, + UShort.class + ); + + QualifiedProperty ACTIVE_COUNT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ActiveCount", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty UNACKNOWLEDGED_COUNT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "UnacknowledgedCount", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty UNCONFIRMED_COUNT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "UnconfirmedCount", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=7"), + -1, + UInteger.class + ); + + QualifiedProperty FILTER = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "Filter", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=586"), + -1, + ContentFilter.class + ); + + UShort getHighestActiveSeverity(); + + void setHighestActiveSeverity(UShort value); + + PropertyType getHighestActiveSeverityNode(); + + UShort getHighestUnackSeverity(); + + void setHighestUnackSeverity(UShort value); + + PropertyType getHighestUnackSeverityNode(); + + UInteger getActiveCount(); + + void setActiveCount(UInteger value); + + PropertyType getActiveCountNode(); + + UInteger getUnacknowledgedCount(); + + void setUnacknowledgedCount(UInteger value); + + PropertyType getUnacknowledgedCountNode(); + + UInteger getUnconfirmedCount(); + + void setUnconfirmedCount(UInteger value); + + PropertyType getUnconfirmedCountNode(); + + ContentFilter getFilter(); + + void setFilter(ContentFilter value); + + PropertyType getFilterNode(); +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmStateVariableTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmStateVariableTypeNode.java new file mode 100644 index 000000000..b5a7d81ec --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/AlarmStateVariableTypeNode.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.variables; + +import java.util.Optional; + +import org.eclipse.milo.opcua.sdk.core.nodes.VariableNode; +import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessLevelExType; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.ContentFilter; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class AlarmStateVariableTypeNode extends BaseDataVariableTypeNode implements AlarmStateVariableType { + public AlarmStateVariableTypeNode(UaNodeContext context, NodeId nodeId, QualifiedName browseName, + LocalizedText displayName, LocalizedText description, UInteger writeMask, + UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + DataValue value, NodeId dataType, Integer valueRank, UInteger[] arrayDimensions, + UByte accessLevel, UByte userAccessLevel, Double minimumSamplingInterval, boolean historizing, + AccessLevelExType accessLevelEx) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, value, dataType, valueRank, arrayDimensions, accessLevel, userAccessLevel, minimumSamplingInterval, historizing, accessLevelEx); + } + + public AlarmStateVariableTypeNode(UaNodeContext context, NodeId nodeId, QualifiedName browseName, + LocalizedText displayName, LocalizedText description, UInteger writeMask, + UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + DataValue value, NodeId dataType, Integer valueRank, UInteger[] arrayDimensions) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, value, dataType, valueRank, arrayDimensions); + } + + @Override + public PropertyTypeNode getHighestActiveSeverityNode() { + Optional propertyNode = getPropertyNode(AlarmStateVariableType.HIGHEST_ACTIVE_SEVERITY); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public UShort getHighestActiveSeverity() { + return getProperty(AlarmStateVariableType.HIGHEST_ACTIVE_SEVERITY).orElse(null); + } + + @Override + public void setHighestActiveSeverity(UShort value) { + setProperty(AlarmStateVariableType.HIGHEST_ACTIVE_SEVERITY, value); + } + + @Override + public PropertyTypeNode getHighestUnackSeverityNode() { + Optional propertyNode = getPropertyNode(AlarmStateVariableType.HIGHEST_UNACK_SEVERITY); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public UShort getHighestUnackSeverity() { + return getProperty(AlarmStateVariableType.HIGHEST_UNACK_SEVERITY).orElse(null); + } + + @Override + public void setHighestUnackSeverity(UShort value) { + setProperty(AlarmStateVariableType.HIGHEST_UNACK_SEVERITY, value); + } + + @Override + public PropertyTypeNode getActiveCountNode() { + Optional propertyNode = getPropertyNode(AlarmStateVariableType.ACTIVE_COUNT); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public UInteger getActiveCount() { + return getProperty(AlarmStateVariableType.ACTIVE_COUNT).orElse(null); + } + + @Override + public void setActiveCount(UInteger value) { + setProperty(AlarmStateVariableType.ACTIVE_COUNT, value); + } + + @Override + public PropertyTypeNode getUnacknowledgedCountNode() { + Optional propertyNode = getPropertyNode(AlarmStateVariableType.UNACKNOWLEDGED_COUNT); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public UInteger getUnacknowledgedCount() { + return getProperty(AlarmStateVariableType.UNACKNOWLEDGED_COUNT).orElse(null); + } + + @Override + public void setUnacknowledgedCount(UInteger value) { + setProperty(AlarmStateVariableType.UNACKNOWLEDGED_COUNT, value); + } + + @Override + public PropertyTypeNode getUnconfirmedCountNode() { + Optional propertyNode = getPropertyNode(AlarmStateVariableType.UNCONFIRMED_COUNT); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public UInteger getUnconfirmedCount() { + return getProperty(AlarmStateVariableType.UNCONFIRMED_COUNT).orElse(null); + } + + @Override + public void setUnconfirmedCount(UInteger value) { + setProperty(AlarmStateVariableType.UNCONFIRMED_COUNT, value); + } + + @Override + public PropertyTypeNode getFilterNode() { + Optional propertyNode = getPropertyNode(AlarmStateVariableType.FILTER); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public ContentFilter getFilter() { + return getProperty(AlarmStateVariableType.FILTER).orElse(null); + } + + @Override + public void setFilter(ContentFilter value) { + setProperty(AlarmStateVariableType.FILTER, value); + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/ReferenceDescriptionVariableType.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/ReferenceDescriptionVariableType.java new file mode 100644 index 000000000..d8c381b85 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/ReferenceDescriptionVariableType.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.variables; + +import org.eclipse.milo.opcua.sdk.core.QualifiedProperty; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceListEntryDataType; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part23/5.3.1 + */ +public interface ReferenceDescriptionVariableType extends BaseDataVariableType { + QualifiedProperty REFERENCE_REFINEMENT = new QualifiedProperty<>( + "http://opcfoundation.org/UA/", + "ReferenceRefinement", + ExpandedNodeId.parse("nsu=http://opcfoundation.org/UA/;i=32660"), + 1, + ReferenceListEntryDataType[].class + ); + + ReferenceListEntryDataType[] getReferenceRefinement(); + + void setReferenceRefinement(ReferenceListEntryDataType[] value); + + PropertyType getReferenceRefinementNode(); +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/ReferenceDescriptionVariableTypeNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/ReferenceDescriptionVariableTypeNode.java new file mode 100644 index 000000000..c68a112a5 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/model/variables/ReferenceDescriptionVariableTypeNode.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.model.variables; + +import java.util.Optional; + +import org.eclipse.milo.opcua.sdk.core.nodes.VariableNode; +import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessLevelExType; +import org.eclipse.milo.opcua.stack.core.types.structured.AccessRestrictionType; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceListEntryDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.RolePermissionType; + +public class ReferenceDescriptionVariableTypeNode extends BaseDataVariableTypeNode implements ReferenceDescriptionVariableType { + public ReferenceDescriptionVariableTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + DataValue value, NodeId dataType, Integer valueRank, UInteger[] arrayDimensions, + UByte accessLevel, UByte userAccessLevel, Double minimumSamplingInterval, boolean historizing, + AccessLevelExType accessLevelEx) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, value, dataType, valueRank, arrayDimensions, accessLevel, userAccessLevel, minimumSamplingInterval, historizing, accessLevelEx); + } + + public ReferenceDescriptionVariableTypeNode(UaNodeContext context, NodeId nodeId, + QualifiedName browseName, LocalizedText displayName, LocalizedText description, + UInteger writeMask, UInteger userWriteMask, RolePermissionType[] rolePermissions, + RolePermissionType[] userRolePermissions, AccessRestrictionType accessRestrictions, + DataValue value, NodeId dataType, Integer valueRank, UInteger[] arrayDimensions) { + super(context, nodeId, browseName, displayName, description, writeMask, userWriteMask, rolePermissions, userRolePermissions, accessRestrictions, value, dataType, valueRank, arrayDimensions); + } + + @Override + public PropertyTypeNode getReferenceRefinementNode() { + Optional propertyNode = getPropertyNode(ReferenceDescriptionVariableType.REFERENCE_REFINEMENT); + return (PropertyTypeNode) propertyNode.orElse(null); + } + + @Override + public ReferenceListEntryDataType[] getReferenceRefinement() { + return getProperty(ReferenceDescriptionVariableType.REFERENCE_REFINEMENT).orElse(null); + } + + @Override + public void setReferenceRefinement(ReferenceListEntryDataType[] value) { + setProperty(ReferenceDescriptionVariableType.REFERENCE_REFINEMENT, value); + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/nodes/UaNode.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/nodes/UaNode.java index 66d741d57..2ed2d8a73 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/nodes/UaNode.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/nodes/UaNode.java @@ -735,10 +735,26 @@ public DataValue getAttribute(AttributeContext context, AttributeId attributeId) attributeId ); - if (attributeId == AttributeId.Value) { - return (DataValue) attributeValue; - } else { - return dv(attributeValue); + switch (attributeId) { + case Value: + return (DataValue) attributeValue; + + case DataTypeDefinition: + case RolePermissions: + case UserRolePermissions: + case AccessRestrictions: + case AccessLevelEx: + // These attributes are either structures or primitive types, and should + // not expose a null value to clients, so if they are null in the node + // that means they are not implemented/support for the node, and we need + // to return Bad_AttributeIdInvalid. + if (attributeValue == null) { + return new DataValue(StatusCodes.Bad_AttributeIdInvalid); + } + + // intentional fall-through + default: + return dv(attributeValue); } } catch (Throwable t) { StatusCode statusCode = UaException.extractStatusCode(t) diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/AbstractServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/AbstractServiceSet.java new file mode 100644 index 000000000..a9d4cd724 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/AbstractServiceSet.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; + +public abstract class AbstractServiceSet { + + public static ResponseHeader createResponseHeader(UaRequestMessageType request) { + return createResponseHeader(request, StatusCode.GOOD); + } + + public static ResponseHeader createResponseHeader(UaRequestMessageType request, long statusCode) { + return createResponseHeader(request, new StatusCode(statusCode)); + } + + public static ResponseHeader createResponseHeader(UaRequestMessageType request, StatusCode serviceResult) { + return new ResponseHeader( + DateTime.now(), + request.getRequestHeader().getRequestHandle(), + serviceResult, + null, null, null + ); + } + + public static ResponseHeader createResponseHeader(UaRequestMessageType request, DiagnosticInfo[] diagnosticInfos) { + // TODO use DiagnosticInfo to create crazy header... + return createResponseHeader(request, StatusCode.GOOD); + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/AttributeServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/AttributeServiceSet.java new file mode 100644 index 000000000..d622caf3d --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/AttributeServiceSet.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +public interface AttributeServiceSet { + + CompletableFuture onRead(ServiceRequestContext context, ReadRequest request); + + CompletableFuture onHistoryRead(ServiceRequestContext context, HistoryReadRequest request); + + CompletableFuture onWrite(ServiceRequestContext context, WriteRequest request); + + CompletableFuture onHistoryUpdate(ServiceRequestContext context, HistoryUpdateRequest request); + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultAttributeHistoryServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultAttributeHistoryServiceSet.java deleted file mode 100644 index b7112734e..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultAttributeHistoryServiceSet.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import java.util.List; -import java.util.stream.Collectors; - -import org.eclipse.milo.opcua.sdk.server.DiagnosticsContext; -import org.eclipse.milo.opcua.sdk.server.OpcUaServer; -import org.eclipse.milo.opcua.sdk.server.Session; -import org.eclipse.milo.opcua.sdk.server.api.services.AttributeHistoryServices.HistoryReadContext; -import org.eclipse.milo.opcua.sdk.server.api.services.AttributeHistoryServices.HistoryUpdateContext; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadDetails; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadResult; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadValueId; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateDetails; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateResult; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.server.services.AttributeHistoryServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; - -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; - -public class DefaultAttributeHistoryServiceSet implements AttributeHistoryServiceSet { - - private final ServiceCounter historyReadMetric = new ServiceCounter(); - private final ServiceCounter historyUpdateMetric = new ServiceCounter(); - - @Override - public void onHistoryRead(ServiceRequest service) { - historyReadMetric.record(service); - - HistoryReadRequest request = (HistoryReadRequest) service.getRequest(); - - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - List nodesToRead = l(request.getNodesToRead()); - - if (nodesToRead.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (nodesToRead.size() > server.getConfig().getLimits().getMaxNodesPerRead().longValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - if (request.getTimestampsToReturn() == null) { - service.setServiceFault(StatusCodes.Bad_TimestampsToReturnInvalid); - return; - } - - DiagnosticsContext diagnosticsContext = new DiagnosticsContext<>(); - - HistoryReadContext context = new HistoryReadContext( - server, - session, - diagnosticsContext - ); - - HistoryReadDetails details = (HistoryReadDetails) request.getHistoryReadDetails().decode( - server.getEncodingContext() - ); - - server.getAddressSpaceManager().historyRead( - context, - details, - request.getTimestampsToReturn(), - nodesToRead - ); - - context.getFuture().thenAccept(values -> { - ResponseHeader header = service.createResponseHeader(); - - DiagnosticInfo[] diagnosticInfos = - diagnosticsContext.getDiagnosticInfos(nodesToRead); - - HistoryReadResponse response = new HistoryReadResponse( - header, - a(values, HistoryReadResult.class), - diagnosticInfos - ); - - service.setResponse(response); - }); - } - - @Override - public void onHistoryUpdate(ServiceRequest service) { - historyUpdateMetric.record(service); - - HistoryUpdateRequest request = (HistoryUpdateRequest) service.getRequest(); - - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - List historyUpdateDetailsList = l(request.getHistoryUpdateDetails()) - .stream().map(e -> (HistoryUpdateDetails) e.decode( - server.getEncodingContext() - )) - .collect(Collectors.toList()); - - if (historyUpdateDetailsList.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (historyUpdateDetailsList.size() > server.getConfig().getLimits().getMaxNodesPerWrite().intValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - DiagnosticsContext diagnosticsContext = new DiagnosticsContext<>(); - - HistoryUpdateContext context = new HistoryUpdateContext( - server, - session, - diagnosticsContext - ); - - server.getAddressSpaceManager().historyUpdate(context, historyUpdateDetailsList); - - context.getFuture().thenAccept(values -> { - ResponseHeader header = service.createResponseHeader(); - - DiagnosticInfo[] diagnosticInfos = - diagnosticsContext.getDiagnosticInfos(historyUpdateDetailsList); - - HistoryUpdateResponse response = new HistoryUpdateResponse( - header, - a(values, HistoryUpdateResult.class), - diagnosticInfos - ); - - service.setResponse(response); - }); - } - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultAttributeServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultAttributeServiceSet.java deleted file mode 100644 index df5cdc89e..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultAttributeServiceSet.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import java.util.List; - -import org.eclipse.milo.opcua.sdk.server.DiagnosticsContext; -import org.eclipse.milo.opcua.sdk.server.OpcUaServer; -import org.eclipse.milo.opcua.sdk.server.Session; -import org.eclipse.milo.opcua.sdk.server.api.services.AttributeServices.ReadContext; -import org.eclipse.milo.opcua.sdk.server.api.services.AttributeServices.WriteContext; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; -import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; -import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; -import org.eclipse.milo.opcua.stack.core.types.structured.ReadRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.ReadResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.WriteRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.WriteResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue; -import org.eclipse.milo.opcua.stack.server.services.AttributeServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; - -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; - -public class DefaultAttributeServiceSet implements AttributeServiceSet { - - @Override - public void onRead(ServiceRequest service) { - ReadRequest request = (ReadRequest) service.getRequest(); - - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - List nodesToRead = l(request.getNodesToRead()); - - if (nodesToRead.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (nodesToRead.size() > server.getConfig().getLimits().getMaxNodesPerRead().longValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - if (request.getMaxAge() < 0d) { - service.setServiceFault(StatusCodes.Bad_MaxAgeInvalid); - return; - } - - if (request.getTimestampsToReturn() == null) { - service.setServiceFault(StatusCodes.Bad_TimestampsToReturnInvalid); - return; - } - - DiagnosticsContext diagnosticsContext = new DiagnosticsContext<>(); - - ReadContext context = new ReadContext(server, session, diagnosticsContext); - - server.getAddressSpaceManager().read( - context, - request.getMaxAge(), - request.getTimestampsToReturn(), - nodesToRead - ); - - context.getFuture().thenAccept(values -> { - ResponseHeader header = service.createResponseHeader(); - - DiagnosticInfo[] diagnosticInfos = - diagnosticsContext.getDiagnosticInfos(nodesToRead); - - ReadResponse response = new ReadResponse( - header, - values.toArray(new DataValue[0]), - diagnosticInfos - ); - - service.setResponse(response); - }); - } - - @Override - public void onWrite(ServiceRequest service) { - WriteRequest request = (WriteRequest) service.getRequest(); - - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - List nodesToWrite = l(request.getNodesToWrite()); - - if (nodesToWrite.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (nodesToWrite.size() > server.getConfig().getLimits().getMaxNodesPerWrite().intValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - DiagnosticsContext diagnosticsContext = new DiagnosticsContext<>(); - - WriteContext context = new WriteContext( - server, - session, - new DiagnosticsContext<>() - ); - - server.getAddressSpaceManager().write(context, nodesToWrite); - - context.getFuture().thenAccept(values -> { - ResponseHeader header = service.createResponseHeader(); - - DiagnosticInfo[] diagnosticInfos = - diagnosticsContext.getDiagnosticInfos(nodesToWrite); - - WriteResponse response = new WriteResponse( - header, - values.toArray(new StatusCode[0]), - diagnosticInfos - ); - - service.setResponse(response); - }); - } - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultMethodServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultMethodServiceSet.java deleted file mode 100644 index 136033b56..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultMethodServiceSet.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import java.util.List; - -import org.eclipse.milo.opcua.sdk.server.DiagnosticsContext; -import org.eclipse.milo.opcua.sdk.server.OpcUaServer; -import org.eclipse.milo.opcua.sdk.server.Session; -import org.eclipse.milo.opcua.sdk.server.api.services.MethodServices.CallContext; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; -import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodResult; -import org.eclipse.milo.opcua.stack.core.types.structured.CallRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.CallResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.server.services.MethodServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; - -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; - -public class DefaultMethodServiceSet implements MethodServiceSet { - - private final ServiceCounter callCounter = new ServiceCounter(); - - @Override - public void onCall(ServiceRequest service) { - callCounter.record(service); - - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - CallRequest request = (CallRequest) service.getRequest(); - - List methodsToCall = l(request.getMethodsToCall()); - - if (methodsToCall.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (methodsToCall.size() > server.getConfig().getLimits().getMaxNodesPerMethodCall().longValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - DiagnosticsContext diagnosticsContext = new DiagnosticsContext<>(); - - CallContext context = new CallContext( - server, - session, - diagnosticsContext - ); - - server.getAddressSpaceManager().call(context, methodsToCall); - - context.getFuture().thenAccept(values -> { - ResponseHeader header = service.createResponseHeader(); - - CallResponse response = new CallResponse( - header, - a(values, CallMethodResult.class), - new DiagnosticInfo[0] - ); - - service.setResponse(response); - }); - } - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultMonitoredItemServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultMonitoredItemServiceSet.java deleted file mode 100644 index c1d0f65bb..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultMonitoredItemServiceSet.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import org.eclipse.milo.opcua.sdk.server.subscriptions.SubscriptionManager; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.server.services.MonitoredItemServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; - -public class DefaultMonitoredItemServiceSet implements MonitoredItemServiceSet { - - private final ServiceCounter createMonitoredItemsMetric = new ServiceCounter(); - private final ServiceCounter modifyMonitoredItemsMetric = new ServiceCounter(); - private final ServiceCounter deleteMonitoredItemsMetric = new ServiceCounter(); - private final ServiceCounter setMonitoringModeMetric = new ServiceCounter(); - private final ServiceCounter setTriggeringMetric = new ServiceCounter(); - - private final SubscriptionManager subscriptionManager; - - public DefaultMonitoredItemServiceSet(SubscriptionManager subscriptionManager) { - this.subscriptionManager = subscriptionManager; - } - - @Override - public void onCreateMonitoredItems(ServiceRequest service) throws UaException { - createMonitoredItemsMetric.record(service); - - subscriptionManager.createMonitoredItems(service); - } - - @Override - public void onModifyMonitoredItems(ServiceRequest service) throws UaException { - modifyMonitoredItemsMetric.record(service); - - subscriptionManager.modifyMonitoredItems(service); - } - - @Override - public void onDeleteMonitoredItems(ServiceRequest service) throws UaException { - deleteMonitoredItemsMetric.record(service); - - subscriptionManager.deleteMonitoredItems(service); - } - - @Override - public void onSetMonitoringMode(ServiceRequest service) { - setMonitoringModeMetric.record(service); - - subscriptionManager.setMonitoringMode(service); - } - - @Override - public void onSetTriggering(ServiceRequest service) { - setTriggeringMetric.record(service); - - subscriptionManager.setTriggering(service); - } - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultNodeManagementServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultNodeManagementServiceSet.java deleted file mode 100644 index f10e1b8cb..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultNodeManagementServiceSet.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import java.util.List; - -import org.eclipse.milo.opcua.sdk.server.DiagnosticsContext; -import org.eclipse.milo.opcua.sdk.server.OpcUaServer; -import org.eclipse.milo.opcua.sdk.server.Session; -import org.eclipse.milo.opcua.sdk.server.api.services.NodeManagementServices.AddNodesContext; -import org.eclipse.milo.opcua.sdk.server.api.services.NodeManagementServices.AddReferencesContext; -import org.eclipse.milo.opcua.sdk.server.api.services.NodeManagementServices.DeleteNodesContext; -import org.eclipse.milo.opcua.sdk.server.api.services.NodeManagementServices.DeleteReferencesContext; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; -import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; -import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesItem; -import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesResult; -import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesItem; -import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesItem; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesItem; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.server.services.NodeManagementServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; - -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; - -public class DefaultNodeManagementServiceSet implements NodeManagementServiceSet { - - @Override - public void onAddNodes(ServiceRequest service) { - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - AddNodesRequest request = (AddNodesRequest) service.getRequest(); - - List nodesToAdd = l(request.getNodesToAdd()); - - if (nodesToAdd.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (nodesToAdd.size() > server.getConfig().getLimits().getMaxNodesPerNodeManagement().longValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - AddNodesContext context = new AddNodesContext( - server, - session, - new DiagnosticsContext<>() - ); - - server.getAddressSpaceManager().addNodes(context, nodesToAdd); - - context.getFuture().thenAccept(results -> { - ResponseHeader header = service.createResponseHeader(); - - AddNodesResponse response = new AddNodesResponse( - header, - a(results, AddNodesResult.class), - new DiagnosticInfo[0] - ); - - service.setResponse(response); - }); - } - - @Override - public void onDeleteNodes(ServiceRequest service) { - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - DeleteNodesRequest request = (DeleteNodesRequest) service.getRequest(); - - List nodesToDelete = l(request.getNodesToDelete()); - - if (nodesToDelete.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (nodesToDelete.size() > server.getConfig().getLimits().getMaxNodesPerNodeManagement().longValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - DeleteNodesContext context = new DeleteNodesContext( - server, - session, - new DiagnosticsContext<>() - ); - - server.getAddressSpaceManager().deleteNodes(context, nodesToDelete); - - context.getFuture().thenAccept(results -> { - ResponseHeader header = service.createResponseHeader(); - - DeleteNodesResponse response = new DeleteNodesResponse( - header, - a(results, StatusCode.class), - new DiagnosticInfo[0] - ); - - service.setResponse(response); - }); - } - - @Override - public void onAddReferences(ServiceRequest service) { - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - AddReferencesRequest request = (AddReferencesRequest) service.getRequest(); - - List referencesToAdd = l(request.getReferencesToAdd()); - - if (referencesToAdd.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (referencesToAdd.size() > server.getConfig().getLimits().getMaxNodesPerNodeManagement().longValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - AddReferencesContext context = new AddReferencesContext( - server, - session, - new DiagnosticsContext<>() - ); - - server.getAddressSpaceManager().addReferences(context, referencesToAdd); - - context.getFuture().thenAccept(results -> { - ResponseHeader header = service.createResponseHeader(); - - AddReferencesResponse response = new AddReferencesResponse( - header, - a(results, StatusCode.class), - new DiagnosticInfo[0] - ); - - service.setResponse(response); - }); - } - - @Override - public void onDeleteReferences(ServiceRequest service) { - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - DeleteReferencesRequest request = (DeleteReferencesRequest) service.getRequest(); - - List referencesToDelete = l(request.getReferencesToDelete()); - - if (referencesToDelete.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (referencesToDelete.size() > server.getConfig().getLimits().getMaxNodesPerNodeManagement().longValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - DeleteReferencesContext context = new DeleteReferencesContext( - server, - session, - new DiagnosticsContext<>() - ); - - server.getAddressSpaceManager().deleteReferences(context, referencesToDelete); - - context.getFuture().thenAccept(results -> { - ResponseHeader header = service.createResponseHeader(); - - DeleteReferencesResponse response = new DeleteReferencesResponse( - header, - a(results, StatusCode.class), - new DiagnosticInfo[0] - ); - - service.setResponse(response); - }); - } - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultQueryServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultQueryServiceSet.java deleted file mode 100644 index f26bcc710..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultQueryServiceSet.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import org.eclipse.milo.opcua.stack.server.services.QueryServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; - -import static org.eclipse.milo.opcua.stack.core.StatusCodes.Bad_ServiceUnsupported; - -public class DefaultQueryServiceSet implements QueryServiceSet { - - private final ServiceCounter queryFirstMetric = new ServiceCounter(); - private final ServiceCounter queryNextMetric = new ServiceCounter(); - - @Override - public void onQueryFirst(ServiceRequest service) { - queryFirstMetric.record(service); - - service.setServiceFault(Bad_ServiceUnsupported); - } - - @Override - public void onQueryNext(ServiceRequest service) { - queryNextMetric.record(service); - - service.setServiceFault(Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultSubscriptionServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultSubscriptionServiceSet.java deleted file mode 100644 index ad375c7a4..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultSubscriptionServiceSet.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import org.eclipse.milo.opcua.sdk.server.OpcUaServer; -import org.eclipse.milo.opcua.sdk.server.Session; -import org.eclipse.milo.opcua.sdk.server.items.MonitoredDataItem; -import org.eclipse.milo.opcua.sdk.server.subscriptions.Subscription; -import org.eclipse.milo.opcua.sdk.server.subscriptions.SubscriptionManager; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; -import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.TransferResult; -import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsResponse; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; -import org.eclipse.milo.opcua.stack.server.services.SubscriptionServiceSet; - -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; - -public class DefaultSubscriptionServiceSet implements SubscriptionServiceSet { - - private final SubscriptionManager subscriptionManager; - - public DefaultSubscriptionServiceSet(SubscriptionManager subscriptionManager) { - this.subscriptionManager = subscriptionManager; - } - - @Override - public void onCreateSubscription(ServiceRequest service) { - subscriptionManager.createSubscription(service); - } - - @Override - public void onModifySubscription(ServiceRequest service) throws UaException { - subscriptionManager.modifySubscription(service); - } - - @Override - public void onDeleteSubscriptions(ServiceRequest service) throws UaException { - subscriptionManager.deleteSubscription(service); - } - - @Override - public void onSetPublishingMode(ServiceRequest service) { - subscriptionManager.setPublishingMode(service); - } - - @Override - public void onPublish(ServiceRequest service) { - subscriptionManager.publish(service); - } - - @Override - public void onRepublish(ServiceRequest service) { - subscriptionManager.republish(service); - } - - @Override - public void onTransferSubscriptions(ServiceRequest service) throws UaException { - TransferSubscriptionsRequest request = (TransferSubscriptionsRequest) service.getRequest(); - - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - List subscriptionIds = l(request.getSubscriptionIds()); - - if (subscriptionIds.isEmpty()) { - throw new UaException(StatusCodes.Bad_NothingToDo); - } - - var results = new ArrayList(); - - for (UInteger subscriptionId : subscriptionIds) { - Subscription subscription = server.getSubscriptions().get(subscriptionId); - - if (subscription == null) { - results.add(new TransferResult( - new StatusCode(StatusCodes.Bad_SubscriptionIdInvalid), - new UInteger[0] - )); - } else { - Session otherSession = subscription.getSession(); - - if (!sessionsHaveSameUser(session, otherSession)) { - results.add(new TransferResult( - new StatusCode(StatusCodes.Bad_UserAccessDenied), - new UInteger[0] - )); - } else { - UInteger[] availableSequenceNumbers; - - synchronized (subscription) { - otherSession.getSubscriptionManager().sendStatusChangeNotification( - subscription, - new StatusCode(StatusCodes.Good_SubscriptionTransferred) - ); - otherSession.getSubscriptionManager().removeSubscription(subscriptionId); - - subscription.setSubscriptionManager(session.getSubscriptionManager()); - subscriptionManager.addSubscription(subscription); - - subscription.getMonitoredItems().values().forEach(item -> item.setSession(session)); - - availableSequenceNumbers = subscription.getAvailableSequenceNumbers(); - - if (request.getSendInitialValues()) { - subscription.getMonitoredItems().values().stream() - .filter(item -> item instanceof MonitoredDataItem) - .map(item -> (MonitoredDataItem) item) - .forEach(MonitoredDataItem::maybeSendLastValue); - } - } - - subscription.getSubscriptionDiagnostics().getTransferRequestCount().increment(); - - ApplicationDescription toClient = session.getClientDescription(); - ApplicationDescription fromClient = otherSession.getClientDescription(); - - if (Objects.equals(toClient, fromClient)) { - subscription.getSubscriptionDiagnostics().getTransferredToSameClientCount().increment(); - } else { - subscription.getSubscriptionDiagnostics().getTransferredToAltClientCount().increment(); - } - - results.add(new TransferResult(StatusCode.GOOD, availableSequenceNumbers)); - } - } - } - - TransferSubscriptionsResponse response = new TransferSubscriptionsResponse( - service.createResponseHeader(), - a(results, TransferResult.class), - new DiagnosticInfo[0] - ); - - service.setResponse(response); - } - - private boolean sessionsHaveSameUser(Session s1, Session s2) { - Object identity1 = s1.getIdentityObject(); - Object identity2 = s2.getIdentityObject(); - - return Objects.equals(identity1, identity2); - } - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultViewServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultViewServiceSet.java deleted file mode 100644 index e66700ae6..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DefaultViewServiceSet.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.stream.Stream; - -import org.eclipse.milo.opcua.sdk.server.DiagnosticsContext; -import org.eclipse.milo.opcua.sdk.server.OpcUaServer; -import org.eclipse.milo.opcua.sdk.server.Session; -import org.eclipse.milo.opcua.sdk.server.api.services.ViewServices.RegisterNodesContext; -import org.eclipse.milo.opcua.sdk.server.api.services.ViewServices.UnregisterNodesContext; -import org.eclipse.milo.opcua.sdk.server.services.helpers.BrowseHelper; -import org.eclipse.milo.opcua.sdk.server.services.helpers.BrowsePathsHelper; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; -import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; -import org.eclipse.milo.opcua.stack.core.types.structured.BrowseDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.BrowseRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResult; -import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesResponse; -import org.eclipse.milo.opcua.stack.core.util.FutureUtils; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; -import org.eclipse.milo.opcua.stack.server.services.ViewServiceSet; - -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; - -public class DefaultViewServiceSet implements ViewServiceSet { - - private final ServiceCounter browseCounter = new ServiceCounter(); - private final ServiceCounter browseNextCounter = new ServiceCounter(); - private final ServiceCounter translateBrowsePathsCounter = new ServiceCounter(); - - private final BrowseHelper browseHelper; - - public DefaultViewServiceSet(ExecutorService executor) { - browseHelper = new BrowseHelper(executor); - } - - @Override - public void onBrowse(ServiceRequest service) { - browseCounter.record(service); - - BrowseRequest request = (BrowseRequest) service.getRequest(); - - DiagnosticsContext diagnosticsContext = new DiagnosticsContext<>(); - - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - List nodesToBrowse = l(request.getNodesToBrowse()); - - if (nodesToBrowse.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; - } - - if (nodesToBrowse.size() > server.getConfig().getLimits().getMaxNodesPerBrowse().intValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; - } - - if (request.getView().getViewId().isNotNull() && - !server.getRegisteredViews().contains(request.getView().getViewId())) { - - service.setServiceFault(StatusCodes.Bad_ViewIdUnknown); - return; - } - - Stream> futures = nodesToBrowse.stream().map( - browseDescription -> - browseHelper.browse( - () -> Optional.of(session), - server, - request.getView(), - request.getRequestedMaxReferencesPerNode(), - browseDescription - ) - ); - - FutureUtils.sequence(futures).thenAccept(results -> { - ResponseHeader header = service.createResponseHeader(); - - DiagnosticInfo[] diagnosticInfos = - diagnosticsContext.getDiagnosticInfos(nodesToBrowse); - - BrowseResponse response = new BrowseResponse( - header, - a(results, BrowseResult.class), - diagnosticInfos - ); - - service.setResponse(response); - }); - } - - @Override - public void onBrowseNext(ServiceRequest service) { - browseNextCounter.record(service); - - browseHelper.browseNext(service); - } - - @Override - public void onTranslateBrowsePaths(ServiceRequest service) { - translateBrowsePathsCounter.record(service); - - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - BrowsePathsHelper browsePathsHelper = new BrowsePathsHelper( - () -> Optional.ofNullable(session), - server - ); - - browsePathsHelper.onTranslateBrowsePaths(service); - } - - @Override - public void onRegisterNodes(ServiceRequest service) throws UaException { - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - RegisterNodesRequest request = (RegisterNodesRequest) service.getRequest(); - - List nodeIds = l(request.getNodesToRegister()); - - if (nodeIds.isEmpty()) { - throw new UaException(StatusCodes.Bad_NothingToDo); - } - - if (nodeIds.size() > server.getConfig().getLimits().getMaxNodesPerRegisterNodes().intValue()) { - throw new UaException(StatusCodes.Bad_TooManyOperations); - } - - RegisterNodesContext context = new RegisterNodesContext(server, session); - - server.getAddressSpaceManager().registerNodes(context, nodeIds); - - context.getFuture().thenAccept(registeredNodeIds -> { - ResponseHeader header = service.createResponseHeader(); - - RegisterNodesResponse response = new RegisterNodesResponse( - header, - registeredNodeIds.toArray(new NodeId[0]) - ); - - service.setResponse(response); - }); - } - - @Override - public void onUnregisterNodes(ServiceRequest service) throws UaException { - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - Session session = service.attr(ServiceAttributes.SESSION_KEY).get(); - - UnregisterNodesRequest request = (UnregisterNodesRequest) service.getRequest(); - - List nodeIds = l(request.getNodesToUnregister()); - - if (nodeIds.isEmpty()) { - throw new UaException(StatusCodes.Bad_NothingToDo); - } - - if (nodeIds.size() > server.getConfig().getLimits().getMaxNodesPerRegisterNodes().intValue()) { - throw new UaException(StatusCodes.Bad_TooManyOperations); - } - - UnregisterNodesContext context = new UnregisterNodesContext(server, session); - - server.getAddressSpaceManager().unregisterNodes(context, nodeIds); - - context.getFuture().thenAccept(registeredNodeIds -> { - ResponseHeader header = service.createResponseHeader(); - - UnregisterNodesResponse response = new UnregisterNodesResponse(header); - - service.setResponse(response); - }); - } - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DiscoveryServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DiscoveryServiceSet.java new file mode 100644 index 000000000..ae98a4bb7 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/DiscoveryServiceSet.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersOnNetworkRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersOnNetworkResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServer2Request; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServer2Response; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +public interface DiscoveryServiceSet { + + + CompletableFuture onFindServers(ServiceRequestContext context, FindServersRequest request); + + CompletableFuture onFindServersOnNetwork( + ServiceRequestContext context, + FindServersOnNetworkRequest request + ); + + CompletableFuture onGetEndpoints( + ServiceRequestContext context, + GetEndpointsRequest request + ); + + CompletableFuture onRegisterServer( + ServiceRequestContext context, + RegisterServerRequest request + ); + + CompletableFuture onRegisterServer2( + ServiceRequestContext context, + RegisterServer2Request request + ); + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/MethodServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/MethodServiceSet.java new file mode 100644 index 000000000..b65c932a7 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/MethodServiceSet.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.types.structured.CallRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CallResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +public interface MethodServiceSet { + + CompletableFuture onCall(ServiceRequestContext context, CallRequest request); + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/MonitoredItemServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/MonitoredItemServiceSet.java new file mode 100644 index 000000000..52222c69e --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/MonitoredItemServiceSet.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.types.structured.CreateMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateMonitoredItemsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteMonitoredItemsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifyMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifyMonitoredItemsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.SetMonitoringModeRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetMonitoringModeResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +public interface MonitoredItemServiceSet { + + CompletableFuture onCreateMonitoredItems( + ServiceRequestContext context, + CreateMonitoredItemsRequest request + ); + + CompletableFuture onModifyMonitoredItems( + ServiceRequestContext context, + ModifyMonitoredItemsRequest request + ); + + CompletableFuture onDeleteMonitoredItems( + ServiceRequestContext context, + DeleteMonitoredItemsRequest request + ); + + CompletableFuture onSetMonitoringMode( + ServiceRequestContext context, + SetMonitoringModeRequest request + ); + + CompletableFuture onSetTriggering( + ServiceRequestContext context, + SetTriggeringRequest request + ); + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/NodeManagementServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/NodeManagementServiceSet.java new file mode 100644 index 000000000..06e105b98 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/NodeManagementServiceSet.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +public interface NodeManagementServiceSet { + + CompletableFuture onAddNodes(ServiceRequestContext context, AddNodesRequest request); + + CompletableFuture onDeleteNodes(ServiceRequestContext context, DeleteNodesRequest request); + + CompletableFuture onAddReferences( + ServiceRequestContext context, + AddReferencesRequest request + ); + + CompletableFuture onDeleteReferences( + ServiceRequestContext context, + DeleteReferencesRequest request + ); + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/Service.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/Service.java new file mode 100644 index 000000000..94a294f9f --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/Service.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.jetbrains.annotations.Nullable; +import org.slf4j.LoggerFactory; + +public enum Service { + + DISCOVERY_FIND_SERVERS, + DISCOVERY_FIND_SERVERS_ON_NETWORK, + DISCOVERY_GET_ENDPOINTS, + DISCOVERY_REGISTER_SERVER, + DISCOVERY_REGISTER_SERVER_2, + + SECURE_CHANNEL_OPEN_SECURE_CHANNEL, + SECURE_CHANNEL_CLOSE_SECURE_CHANNEL, + + SESSION_CREATE_SESSION, + SESSION_ACTIVATE_SESSION, + SESSION_CLOSE_SESSION, + SESSION_CANCEL, + + NODE_MANAGEMENT_ADD_NODES, + NODE_MANAGEMENT_ADD_REFERENCES, + NODE_MANAGEMENT_DELETE_NODES, + NODE_MANAGEMENT_DELETE_REFERENCES, + + VIEW_BROWSE, + VIEW_BROWSE_NEXT, + VIEW_TRANSLATE_BROWSE_PATHS, + VIEW_REGISTER_NODES, + VIEW_UNREGISTER_NODES, + + QUERY_QUERY_FIRST, + QUERY_QUERY_NEXT, + + ATTRIBUTE_READ, + ATTRIBUTE_HISTORY_READ, + ATTRIBUTE_WRITE, + ATTRIBUTE_HISTORY_UPDATE, + + METHOD_CALL, + + MONITORED_ITEM_CREATE_MONITORED_ITEMS, + MONITORED_ITEM_MODIFY_MONITORED_ITEMS, + MONITORED_ITEM_SET_MONITORING_MODE, + MONITORED_ITEM_SET_TRIGGERING, + MONITORED_ITEM_DELETE_MONITORED_ITEMS, + + SUBSCRIPTION_CREATE_SUBSCRIPTION, + SUBSCRIPTION_MODIFY_SUBSCRIPTION, + SUBSCRIPTION_SET_PUBLISHING_MODE, + SUBSCRIPTION_PUBLISH, + SUBSCRIPTION_REPUBLISH, + SUBSCRIPTION_TRANSFER_SUBSCRIPTIONS, + SUBSCRIPTION_DELETE_SUBSCRIPTIONS; + + + public static @Nullable Service from(ExpandedNodeId typeId) { + Object identifier = typeId.getIdentifier(); + if (!(identifier instanceof UInteger)) { + return null; + } + int id = ((UInteger) identifier).intValue(); + + switch (id) { + //@formatter:off + case 420: return DISCOVERY_FIND_SERVERS; + case 12190: return DISCOVERY_FIND_SERVERS_ON_NETWORK; + case 426: return DISCOVERY_GET_ENDPOINTS; + case 435: return DISCOVERY_REGISTER_SERVER; + case 12193: return DISCOVERY_REGISTER_SERVER_2; + + case 444: return SECURE_CHANNEL_OPEN_SECURE_CHANNEL; + case 450: return SECURE_CHANNEL_CLOSE_SECURE_CHANNEL; + + case 459: return SESSION_CREATE_SESSION; + case 465: return SESSION_ACTIVATE_SESSION; + case 471: return SESSION_CLOSE_SESSION; + case 477: return SESSION_CANCEL; + + case 486: return NODE_MANAGEMENT_ADD_NODES; + case 492: return NODE_MANAGEMENT_ADD_REFERENCES; + case 498: return NODE_MANAGEMENT_DELETE_NODES; + case 504: return NODE_MANAGEMENT_DELETE_REFERENCES; + + case 525: return VIEW_BROWSE; + case 531: return VIEW_BROWSE_NEXT; + case 552: return VIEW_TRANSLATE_BROWSE_PATHS; + case 558: return VIEW_REGISTER_NODES; + case 564: return VIEW_UNREGISTER_NODES; + + case 613: return QUERY_QUERY_FIRST; + case 619: return QUERY_QUERY_NEXT; + + case 629: return ATTRIBUTE_READ; + case 662: return ATTRIBUTE_HISTORY_READ; + case 671: return ATTRIBUTE_WRITE; + case 698: return ATTRIBUTE_HISTORY_UPDATE; + + case 710: return METHOD_CALL; + + case 749: return MONITORED_ITEM_CREATE_MONITORED_ITEMS; + case 761: return MONITORED_ITEM_MODIFY_MONITORED_ITEMS; + case 767: return MONITORED_ITEM_SET_MONITORING_MODE; + case 773: return MONITORED_ITEM_SET_TRIGGERING; + case 779: return MONITORED_ITEM_DELETE_MONITORED_ITEMS; + + case 785: return SUBSCRIPTION_CREATE_SUBSCRIPTION; + case 791: return SUBSCRIPTION_MODIFY_SUBSCRIPTION; + case 797: return SUBSCRIPTION_SET_PUBLISHING_MODE; + case 824: return SUBSCRIPTION_PUBLISH; + case 830: return SUBSCRIPTION_REPUBLISH; + case 839: return SUBSCRIPTION_TRANSFER_SUBSCRIPTIONS; + case 845: return SUBSCRIPTION_DELETE_SUBSCRIPTIONS; + //@formatter:on + default: + LoggerFactory.getLogger(Service.class) + .warn("Unknown service id: " + id); + return null; + } + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/ServiceAttributes.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/ServiceAttributes.java deleted file mode 100644 index 8c00dedf5..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/ServiceAttributes.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import io.netty.util.AttributeKey; -import org.eclipse.milo.opcua.sdk.server.OpcUaServer; -import org.eclipse.milo.opcua.sdk.server.Session; - -public interface ServiceAttributes { - - AttributeKey SERVER_KEY = AttributeKey.valueOf("server"); - - AttributeKey SESSION_KEY = AttributeKey.valueOf("session"); - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/ServiceCounter.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/ServiceCounter.java deleted file mode 100644 index 83c1a7695..000000000 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/ServiceCounter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.sdk.server.services; - -import java.util.concurrent.atomic.LongAdder; - -import org.eclipse.milo.opcua.stack.core.types.structured.ServiceCounterDataType; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - -public class ServiceCounter { - - private final LongAdder totalCount = new LongAdder(); - private final LongAdder errorCount = new LongAdder(); - - public void record(ServiceRequest service) { - service.getFuture().whenComplete((r, ex) -> { - totalCount.increment(); - - if (ex != null) { - errorCount.increment(); - } - }); - } - - public ServiceCounterDataType getServiceCounter() { - return new ServiceCounterDataType( - uint(totalCount.sum()), - uint(errorCount.sum()) - ); - } - -} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/SessionServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/SessionServiceSet.java new file mode 100644 index 000000000..51d496c59 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/SessionServiceSet.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CancelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CancelResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSessionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +public interface SessionServiceSet { + + CompletableFuture onCreateSession( + ServiceRequestContext context, + CreateSessionRequest request + ); + + CompletableFuture onActivateSession( + ServiceRequestContext context, + ActivateSessionRequest request + ); + + CompletableFuture onCloseSession( + ServiceRequestContext context, + CloseSessionRequest request + ); + + CompletableFuture onCancel(ServiceRequestContext context, CancelRequest request); + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/SubscriptionServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/SubscriptionServiceSet.java new file mode 100644 index 000000000..8d4103749 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/SubscriptionServiceSet.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSubscriptionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSubscriptionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteSubscriptionsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteSubscriptionsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifySubscriptionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifySubscriptionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RepublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RepublishResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.SetPublishingModeRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetPublishingModeResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +public interface SubscriptionServiceSet { + + CompletableFuture onCreateSubscription( + ServiceRequestContext context, + CreateSubscriptionRequest request + ); + + CompletableFuture onModifySubscription( + ServiceRequestContext context, + ModifySubscriptionRequest request + ); + + CompletableFuture onDeleteSubscriptions( + ServiceRequestContext context, + DeleteSubscriptionsRequest request + ); + + CompletableFuture onTransferSubscriptions( + ServiceRequestContext context, + TransferSubscriptionsRequest request + ); + + CompletableFuture onSetPublishingMode( + ServiceRequestContext context, + SetPublishingModeRequest request + ); + + CompletableFuture onPublish(ServiceRequestContext context, PublishRequest request); + + CompletableFuture onRepublish(ServiceRequestContext context, RepublishRequest request); + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/ViewServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/ViewServiceSet.java new file mode 100644 index 000000000..d2a1f9ec7 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/ViewServiceSet.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +public interface ViewServiceSet { + + CompletableFuture onBrowse(ServiceRequestContext context, BrowseRequest request); + + CompletableFuture onBrowseNext(ServiceRequestContext context, BrowseNextRequest request); + + CompletableFuture onTranslateBrowsePaths( + ServiceRequestContext context, + TranslateBrowsePathsToNodeIdsRequest request + ); + + CompletableFuture onRegisterNodes( + ServiceRequestContext context, + RegisterNodesRequest request + ); + + CompletableFuture onUnregisterNodes( + ServiceRequestContext context, + UnregisterNodesRequest request + ); + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultAttributeServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultAttributeServiceSet.java new file mode 100644 index 000000000..0d04d4a3c --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultAttributeServiceSet.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services.impl; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.milo.opcua.sdk.server.DiagnosticsContext; +import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.Session; +import org.eclipse.milo.opcua.sdk.server.api.services.AttributeHistoryServices.HistoryReadContext; +import org.eclipse.milo.opcua.sdk.server.api.services.AttributeHistoryServices.HistoryUpdateContext; +import org.eclipse.milo.opcua.sdk.server.api.services.AttributeServices.ReadContext; +import org.eclipse.milo.opcua.sdk.server.api.services.AttributeServices.WriteContext; +import org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.AttributeServiceSet; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadResult; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadValueId; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateDetails; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateResult; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; +import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; +import static org.eclipse.milo.opcua.stack.core.util.FutureUtils.failedUaFuture; + +public class DefaultAttributeServiceSet extends AbstractServiceSet implements AttributeServiceSet { + + private final OpcUaServer server; + + public DefaultAttributeServiceSet(OpcUaServer server) { + this.server = server; + } + + @Override + public CompletableFuture onRead(ServiceRequestContext context, ReadRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + List nodesToRead = List.of(request.getNodesToRead()); + + if (nodesToRead.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (nodesToRead.size() > server.getConfig().getLimits().getMaxNodesPerRead().longValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + if (request.getMaxAge() < 0d) { + return failedUaFuture(StatusCodes.Bad_MaxAgeInvalid); + } + + if (request.getTimestampsToReturn() == null) { + return failedUaFuture(StatusCodes.Bad_TimestampsToReturnInvalid); + } + + var diagnosticsContext = new DiagnosticsContext(); + + var readContext = new ReadContext( + server, + session, + diagnosticsContext, + request.getRequestHeader().getAuditEntryId(), + request.getRequestHeader().getTimeoutHint(), + request.getRequestHeader().getAdditionalHeader() + ); + + session.getSessionDiagnostics().getReadCount().record(readContext.getFuture()); + session.getSessionDiagnostics().getTotalRequestCount().record(readContext.getFuture()); + + server.getAddressSpaceManager().read( + readContext, + request.getMaxAge(), + request.getTimestampsToReturn(), + nodesToRead + ); + + return readContext.getFuture().thenApply(values -> { + DiagnosticInfo[] diagnosticInfos = + diagnosticsContext.getDiagnosticInfos(nodesToRead); + + ResponseHeader header = createResponseHeader(request); + + return new ReadResponse(header, values.toArray(DataValue[]::new), diagnosticInfos); + }); + } + + @Override + public CompletableFuture onHistoryRead( + ServiceRequestContext context, + HistoryReadRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + List nodesToRead = l(request.getNodesToRead()); + + if (nodesToRead.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (nodesToRead.size() > server.getConfig().getLimits().getMaxNodesPerRead().longValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + if (request.getTimestampsToReturn() == null) { + return failedUaFuture(StatusCodes.Bad_TimestampsToReturnInvalid); + } + + var diagnosticsContext = new DiagnosticsContext(); + + var historyReadContext = new HistoryReadContext( + server, + session, + diagnosticsContext, + request.getRequestHeader().getAuditEntryId(), + request.getRequestHeader().getTimeoutHint(), + request.getRequestHeader().getAdditionalHeader() + ); + + session.getSessionDiagnostics().getHistoryReadCount().record(historyReadContext.getFuture()); + session.getSessionDiagnostics().getTotalRequestCount().record(historyReadContext.getFuture()); + + ExtensionObject xo = request.getHistoryReadDetails(); + HistoryReadDetails details = (HistoryReadDetails) xo.decode(server.getEncodingContext()); + + server.getAddressSpaceManager().historyRead( + historyReadContext, + details, + request.getTimestampsToReturn(), + nodesToRead + ); + + return historyReadContext.getFuture().thenApply(values -> { + ResponseHeader header = createResponseHeader(request); + + DiagnosticInfo[] diagnosticInfos = + diagnosticsContext.getDiagnosticInfos(nodesToRead); + + return new HistoryReadResponse(header, values.toArray(HistoryReadResult[]::new), diagnosticInfos); + }); + } + + @Override + public CompletableFuture onWrite(ServiceRequestContext context, WriteRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + List nodesToWrite = List.of(request.getNodesToWrite()); + + if (nodesToWrite.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (nodesToWrite.size() > server.getConfig().getLimits().getMaxNodesPerWrite().intValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + var diagnosticsContext = new DiagnosticsContext(); + + var writeContext = new WriteContext( + server, + session, + diagnosticsContext, + request.getRequestHeader().getAuditEntryId(), + request.getRequestHeader().getTimeoutHint(), + request.getRequestHeader().getAdditionalHeader() + ); + + session.getSessionDiagnostics().getWriteCount().record(writeContext.getFuture()); + session.getSessionDiagnostics().getTotalRequestCount().record(writeContext.getFuture()); + + server.getAddressSpaceManager().write(writeContext, nodesToWrite); + + return writeContext.getFuture().thenApply(values -> { + ResponseHeader header = createResponseHeader(request); + + DiagnosticInfo[] diagnosticInfos = + diagnosticsContext.getDiagnosticInfos(nodesToWrite); + + return new WriteResponse(header, values.toArray(StatusCode[]::new), diagnosticInfos); + }); + } + + @Override + public CompletableFuture onHistoryUpdate( + ServiceRequestContext context, + HistoryUpdateRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + List historyUpdateDetailsList = Stream.of(request.getHistoryUpdateDetails()) + .map(xo -> (HistoryUpdateDetails) xo.decode(server.getEncodingContext())) + .collect(Collectors.toList()); + + if (historyUpdateDetailsList.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (historyUpdateDetailsList.size() > server.getConfig().getLimits().getMaxNodesPerWrite().intValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + var diagnosticsContext = new DiagnosticsContext(); + + var historyUpdateContext = new HistoryUpdateContext( + server, + session, + diagnosticsContext, + request.getRequestHeader().getAuditEntryId(), + request.getRequestHeader().getTimeoutHint(), + request.getRequestHeader().getAdditionalHeader() + ); + + server.getAddressSpaceManager().historyUpdate(historyUpdateContext, historyUpdateDetailsList); + + return historyUpdateContext.getFuture().thenApply(values -> { + ResponseHeader header = createResponseHeader(request); + + DiagnosticInfo[] diagnosticInfos = + diagnosticsContext.getDiagnosticInfos(historyUpdateDetailsList); + + return new HistoryUpdateResponse(header, values.toArray(HistoryUpdateResult[]::new), diagnosticInfos); + }); + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultDiscoveryServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultDiscoveryServiceSet.java new file mode 100644 index 000000000..8b339391a --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultDiscoveryServiceSet.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services.impl; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.api.config.EndpointConfig; +import org.eclipse.milo.opcua.sdk.server.services.DiscoveryServiceSet; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; +import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersOnNetworkRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersOnNetworkResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.FindServersResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServer2Request; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServer2Response; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerResponse; +import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.util.stream.Collectors.toList; +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; +import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; +import static org.eclipse.milo.opcua.stack.core.util.FutureUtils.failedUaFuture; + +public class DefaultDiscoveryServiceSet implements DiscoveryServiceSet { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final OpcUaServer server; + + public DefaultDiscoveryServiceSet(OpcUaServer server) { + this.server = server; + } + + @Override + public CompletableFuture onGetEndpoints(ServiceRequestContext context, GetEndpointsRequest request) { + List profileUris = request.getProfileUris() != null ? + List.of(request.getProfileUris()) : + Collections.emptyList(); + + List allEndpoints = server.getApplicationContext() + .getEndpointDescriptions() + .stream() + .filter(ed -> !ed.getEndpointUrl().endsWith("/discovery")) + .filter(ed -> filterProfileUris(ed, profileUris)) + .distinct() + .collect(Collectors.toList()); + + ApplicationDescription filteredApplicationDescription = + getFilteredApplicationDescription(request.getEndpointUrl()); + + List matchingEndpoints = allEndpoints.stream() + .filter(endpoint -> filterEndpointUrls(endpoint, request.getEndpointUrl())) + .map(endpoint -> + replaceApplicationDescription( + endpoint, + filteredApplicationDescription + ) + ) + .distinct() + .collect(toList()); + + var response = new GetEndpointsResponse( + createResponseHeader(request), + matchingEndpoints.isEmpty() ? + allEndpoints.toArray(new EndpointDescription[0]) : + matchingEndpoints.toArray(new EndpointDescription[0]) + ); + + return CompletableFuture.completedFuture(response); + } + + @Override + public CompletableFuture onFindServers(ServiceRequestContext context, FindServersRequest request) { + List serverUris = request.getServerUris() != null ? + List.of(request.getServerUris()) : + Collections.emptyList(); + + List applicationDescriptions = + List.of(getFilteredApplicationDescription(request.getEndpointUrl())); + + applicationDescriptions = applicationDescriptions.stream() + .filter(ad -> filterServerUris(ad, serverUris)) + .collect(toList()); + + var response = new FindServersResponse( + createResponseHeader(request), + a(applicationDescriptions, ApplicationDescription.class) + ); + + return CompletableFuture.completedFuture(response); + } + + @Override + public CompletableFuture onFindServersOnNetwork(ServiceRequestContext context, FindServersOnNetworkRequest request) { + return failedUaFuture(StatusCodes.Bad_ServiceUnsupported); + } + + @Override + public CompletableFuture onRegisterServer(ServiceRequestContext context, RegisterServerRequest request) { + return failedUaFuture(StatusCodes.Bad_ServiceUnsupported); + } + + @Override + public CompletableFuture onRegisterServer2(ServiceRequestContext context, RegisterServer2Request request) { + return failedUaFuture(StatusCodes.Bad_ServiceUnsupported); + } + + private boolean filterProfileUris(EndpointDescription endpoint, List profileUris) { + return profileUris.size() == 0 || profileUris.contains(endpoint.getTransportProfileUri()); + } + + private boolean filterEndpointUrls(EndpointDescription endpoint, String endpointUrl) { + try { + String requestedHost = EndpointUtil.getHost(endpointUrl); + String endpointHost = EndpointUtil.getHost(endpoint.getEndpointUrl()); + + return Objects.requireNonNullElse(requestedHost, "").equalsIgnoreCase(endpointHost); + } catch (Throwable e) { + logger.debug("Unable to create URI.", e); + return false; + } + } + + private EndpointDescription replaceApplicationDescription( + EndpointDescription endpoint, + ApplicationDescription applicationDescription) { + + return new EndpointDescription( + endpoint.getEndpointUrl(), + applicationDescription, + endpoint.getServerCertificate(), + endpoint.getSecurityMode(), + endpoint.getSecurityPolicyUri(), + endpoint.getUserIdentityTokens(), + endpoint.getTransportProfileUri(), + endpoint.getSecurityLevel() + ); + } + + private ApplicationDescription getFilteredApplicationDescription(String endpointUrl) { + List allDiscoveryUrls = server.getConfig().getEndpoints() + .stream() + .map(EndpointConfig::getEndpointUrl) + .filter(url -> url.endsWith("/discovery")) + .distinct() + .collect(toList()); + + if (allDiscoveryUrls.isEmpty()) { + allDiscoveryUrls = server.getConfig().getEndpoints() + .stream() + .map(EndpointConfig::getEndpointUrl) + .distinct() + .collect(toList()); + } + + List matchingDiscoveryUrls = allDiscoveryUrls.stream() + .filter(discoveryUrl -> { + try { + + String requestedHost = EndpointUtil.getHost(endpointUrl); + String discoveryHost = EndpointUtil.getHost(discoveryUrl); + + logger.debug("requestedHost={}, discoveryHost={}", requestedHost, discoveryHost); + + return Objects.requireNonNullElse(requestedHost, "").equalsIgnoreCase(discoveryHost); + } catch (Throwable e) { + logger.debug("Unable to create URI.", e); + return false; + } + }) + .distinct() + .collect(toList()); + + + logger.debug("Matching discovery URLs: {}", matchingDiscoveryUrls); + + return new ApplicationDescription( + server.getConfig().getApplicationUri(), + server.getConfig().getProductUri(), + server.getConfig().getApplicationName(), + ApplicationType.Server, + null, + null, + matchingDiscoveryUrls.isEmpty() ? + allDiscoveryUrls.toArray(new String[0]) : + matchingDiscoveryUrls.toArray(new String[0]) + ); + } + + private boolean filterServerUris(ApplicationDescription ad, List serverUris) { + return serverUris.size() == 0 || serverUris.contains(ad.getApplicationUri()); + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultMethodServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultMethodServiceSet.java new file mode 100644 index 000000000..b3381aa60 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultMethodServiceSet.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services.impl; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.server.DiagnosticsContext; +import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.Session; +import org.eclipse.milo.opcua.sdk.server.api.services.MethodServices.CallContext; +import org.eclipse.milo.opcua.sdk.server.services.MethodServiceSet; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; +import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodResult; +import org.eclipse.milo.opcua.stack.core.types.structured.CallRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CallResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; +import static org.eclipse.milo.opcua.stack.core.util.FutureUtils.failedUaFuture; + +public class DefaultMethodServiceSet implements MethodServiceSet { + + private final OpcUaServer server; + + public DefaultMethodServiceSet(OpcUaServer server) { + this.server = server; + } + + @Override + public CompletableFuture onCall(ServiceRequestContext context, CallRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + List methodsToCall = List.of(request.getMethodsToCall()); + + if (methodsToCall.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (methodsToCall.size() > server.getConfig().getLimits().getMaxNodesPerMethodCall().longValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + var diagnosticsContext = new DiagnosticsContext(); + + var callContext = new CallContext( + server, + session, + diagnosticsContext, + request.getRequestHeader().getAuditEntryId(), + request.getRequestHeader().getTimeoutHint(), + request.getRequestHeader().getAdditionalHeader() + ); + + session.getSessionDiagnostics().getCallCount().record(callContext.getFuture()); + session.getSessionDiagnostics().getTotalRequestCount().record(callContext.getFuture()); + + server.getAddressSpaceManager().call(callContext, methodsToCall); + + return callContext.getFuture().thenApply(values -> { + ResponseHeader header = createResponseHeader(request); + + return new CallResponse(header, values.toArray(CallMethodResult[]::new), new DiagnosticInfo[0]); + }); + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultMonitoredItemServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultMonitoredItemServiceSet.java new file mode 100644 index 000000000..039862883 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultMonitoredItemServiceSet.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services.impl; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.Session; +import org.eclipse.milo.opcua.sdk.server.services.MonitoredItemServiceSet; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateMonitoredItemsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteMonitoredItemsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifyMonitoredItemsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifyMonitoredItemsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.SetMonitoringModeRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetMonitoringModeResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +public class DefaultMonitoredItemServiceSet implements MonitoredItemServiceSet { + + private final OpcUaServer server; + + public DefaultMonitoredItemServiceSet(OpcUaServer server) { + this.server = server; + } + + @Override + public CompletableFuture onCreateMonitoredItems( + ServiceRequestContext context, + CreateMonitoredItemsRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().createMonitoredItems(context, request); + + session.getSessionDiagnostics().getCreateMonitoredItemsCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onModifyMonitoredItems(ServiceRequestContext context, ModifyMonitoredItemsRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().modifyMonitoredItems(context, request); + + session.getSessionDiagnostics().getModifyMonitoredItemsCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onDeleteMonitoredItems( + ServiceRequestContext context, + DeleteMonitoredItemsRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().deleteMonitoredItems(context, request); + + session.getSessionDiagnostics().getDeleteMonitoredItemsCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onSetMonitoringMode(ServiceRequestContext context, SetMonitoringModeRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().setMonitoringMode(context, request); + + session.getSessionDiagnostics().getSetMonitoringModeCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onSetTriggering(ServiceRequestContext context, SetTriggeringRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().setTriggering(context, request); + + session.getSessionDiagnostics().getSetTriggeringCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultNodeManagementServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultNodeManagementServiceSet.java new file mode 100644 index 000000000..9109c4069 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultNodeManagementServiceSet.java @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services.impl; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.server.DiagnosticsContext; +import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.Session; +import org.eclipse.milo.opcua.sdk.server.api.services.NodeManagementServices.AddNodesContext; +import org.eclipse.milo.opcua.sdk.server.api.services.NodeManagementServices.AddReferencesContext; +import org.eclipse.milo.opcua.sdk.server.api.services.NodeManagementServices.DeleteNodesContext; +import org.eclipse.milo.opcua.sdk.server.api.services.NodeManagementServices.DeleteReferencesContext; +import org.eclipse.milo.opcua.sdk.server.services.NodeManagementServiceSet; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesItem; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesResult; +import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesItem; +import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesItem; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesItem; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; +import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; +import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; +import static org.eclipse.milo.opcua.stack.core.util.FutureUtils.failedUaFuture; + +public class DefaultNodeManagementServiceSet implements NodeManagementServiceSet { + + private final OpcUaServer server; + + public DefaultNodeManagementServiceSet(OpcUaServer server) { + this.server = server; + } + + @Override + public CompletableFuture onAddNodes(ServiceRequestContext context, AddNodesRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = addNodes(request, session); + + session.getSessionDiagnostics().getAddNodesCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onDeleteNodes(ServiceRequestContext context, DeleteNodesRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = deleteNodes(request, session); + + session.getSessionDiagnostics().getDeleteNodesCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onAddReferences(ServiceRequestContext context, AddReferencesRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = addReferences(request, session); + + session.getSessionDiagnostics().getAddReferencesCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onDeleteReferences(ServiceRequestContext context, DeleteReferencesRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = deleteReferences(request, session); + + session.getSessionDiagnostics().getDeleteReferencesCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + private CompletableFuture addNodes(AddNodesRequest request, Session session) { + List nodesToAdd = List.of(request.getNodesToAdd()); + + if (nodesToAdd.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (nodesToAdd.size() > server.getConfig().getLimits().getMaxNodesPerNodeManagement().longValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + var addNodesContext = new AddNodesContext( + server, + session, + new DiagnosticsContext<>(), + request.getRequestHeader().getAuditEntryId(), + request.getRequestHeader().getTimeoutHint(), + request.getRequestHeader().getAdditionalHeader() + ); + + server.getAddressSpaceManager().addNodes(addNodesContext, nodesToAdd); + + return addNodesContext.getFuture().thenApply(results -> { + ResponseHeader header = createResponseHeader(request); + + return new AddNodesResponse( + header, + results.toArray(AddNodesResult[]::new), + new DiagnosticInfo[0] + ); + }); + } + + private CompletableFuture deleteNodes(DeleteNodesRequest request, Session session) { + List nodesToDelete = l(request.getNodesToDelete()); + + if (nodesToDelete.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (nodesToDelete.size() > server.getConfig().getLimits().getMaxNodesPerNodeManagement().longValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + var deleteNodesContext = new DeleteNodesContext( + server, + session, + new DiagnosticsContext<>(), + request.getRequestHeader().getAuditEntryId(), + request.getRequestHeader().getTimeoutHint(), + request.getRequestHeader().getAdditionalHeader() + ); + + server.getAddressSpaceManager().deleteNodes(deleteNodesContext, nodesToDelete); + + return deleteNodesContext.getFuture().thenApply(results -> { + ResponseHeader header = createResponseHeader(request); + + return new DeleteNodesResponse( + header, + results.toArray(StatusCode[]::new), + new DiagnosticInfo[0] + ); + }); + } + + private CompletableFuture addReferences(AddReferencesRequest request, Session session) { + List referencesToAdd = List.of(request.getReferencesToAdd()); + + if (referencesToAdd.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (referencesToAdd.size() > server.getConfig().getLimits().getMaxNodesPerNodeManagement().longValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + var addReferencesContext = new AddReferencesContext( + server, + session, + new DiagnosticsContext<>(), + request.getRequestHeader().getAuditEntryId(), + request.getRequestHeader().getTimeoutHint(), + request.getRequestHeader().getAdditionalHeader() + ); + + server.getAddressSpaceManager().addReferences(addReferencesContext, referencesToAdd); + + return addReferencesContext.getFuture().thenApply(results -> { + ResponseHeader header = createResponseHeader(request); + + return new AddReferencesResponse( + header, + a(results, StatusCode.class), + new DiagnosticInfo[0] + ); + }); + } + + private CompletableFuture deleteReferences( + DeleteReferencesRequest request, + Session session + ) { + + List referencesToDelete = List.of(request.getReferencesToDelete()); + + if (referencesToDelete.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (referencesToDelete.size() > server.getConfig().getLimits().getMaxNodesPerNodeManagement().longValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + var deleteReferencesContext = new DeleteReferencesContext( + server, + session, + new DiagnosticsContext<>(), + request.getRequestHeader().getAuditEntryId(), + request.getRequestHeader().getTimeoutHint(), + request.getRequestHeader().getAdditionalHeader() + ); + + server.getAddressSpaceManager().deleteReferences(deleteReferencesContext, referencesToDelete); + + return deleteReferencesContext.getFuture().thenApply(results -> { + ResponseHeader header = createResponseHeader(request); + + return new DeleteReferencesResponse( + header, + results.toArray(StatusCode[]::new), + new DiagnosticInfo[0] + ); + }); + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultSessionServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultSessionServiceSet.java new file mode 100644 index 000000000..4e8248cfb --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultSessionServiceSet.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services.impl; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.SessionManager; +import org.eclipse.milo.opcua.sdk.server.diagnostics.ServerDiagnosticsSummary; +import org.eclipse.milo.opcua.sdk.server.services.SessionServiceSet; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CancelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CancelResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSessionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; + +public class DefaultSessionServiceSet implements SessionServiceSet { + + private final OpcUaServer server; + + public DefaultSessionServiceSet(OpcUaServer server) { + this.server = server; + } + + @Override + public CompletableFuture onCreateSession(ServiceRequestContext context, CreateSessionRequest request) { + ServerDiagnosticsSummary serverDiagnosticsSummary = server.getDiagnosticsSummary(); + + SessionManager sessionManager = server.getSessionManager(); + + try { + CreateSessionResponse response = sessionManager.createSession(context, request); + + serverDiagnosticsSummary.getCumulatedSessionCount().increment(); + + return CompletableFuture.completedFuture(response); + } catch (UaException e) { + serverDiagnosticsSummary.getRejectedSessionCount().increment(); + + if (e.getStatusCode().isSecurityError()) { + serverDiagnosticsSummary.getSecurityRejectedSessionCount().increment(); + } + + return CompletableFuture.failedFuture(e); + } + } + + @Override + public CompletableFuture onActivateSession(ServiceRequestContext context, ActivateSessionRequest request) { + SessionManager sessionManager = server.getSessionManager(); + + try { + ActivateSessionResponse response = sessionManager.activateSession(context, request); + + return CompletableFuture.completedFuture(response); + } catch (UaException e) { + ServerDiagnosticsSummary serverDiagnosticsSummary = server.getDiagnosticsSummary(); + + serverDiagnosticsSummary.getRejectedSessionCount().increment(); + + if (e.getStatusCode().isSecurityError()) { + serverDiagnosticsSummary.getSecurityRejectedSessionCount().increment(); + } + + return CompletableFuture.failedFuture(e); + } + } + + @Override + public CompletableFuture onCloseSession(ServiceRequestContext context, CloseSessionRequest request) { + SessionManager sessionManager = server.getSessionManager(); + + try { + CloseSessionResponse response = sessionManager.closeSession(request, context); + + return CompletableFuture.completedFuture(response); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + } + + @Override + public CompletableFuture onCancel(ServiceRequestContext context, CancelRequest request) { + var response = new CancelResponse(createResponseHeader(request), UInteger.MIN); + + return CompletableFuture.completedFuture(response); + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultSubscriptionServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultSubscriptionServiceSet.java new file mode 100644 index 000000000..30957044c --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultSubscriptionServiceSet.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.Session; +import org.eclipse.milo.opcua.sdk.server.items.MonitoredDataItem; +import org.eclipse.milo.opcua.sdk.server.services.SubscriptionServiceSet; +import org.eclipse.milo.opcua.sdk.server.subscriptions.Subscription; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSubscriptionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSubscriptionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteSubscriptionsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.DeleteSubscriptionsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifySubscriptionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.ModifySubscriptionResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RepublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RepublishResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.SetPublishingModeRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.SetPublishingModeResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.TransferResult; +import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsResponse; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; +import static org.eclipse.milo.opcua.stack.core.util.FutureUtils.failedUaFuture; + +public class DefaultSubscriptionServiceSet implements SubscriptionServiceSet { + + private final OpcUaServer server; + + public DefaultSubscriptionServiceSet(OpcUaServer server) { + this.server = server; + } + + @Override + public CompletableFuture onCreateSubscription( + ServiceRequestContext context, + CreateSubscriptionRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().createSubscription(request); + + session.getSessionDiagnostics().getCreateSubscriptionCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onModifySubscription( + ServiceRequestContext context, + ModifySubscriptionRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().modifySubscription(request); + + session.getSessionDiagnostics().getModifySubscriptionCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onDeleteSubscriptions( + ServiceRequestContext context, + DeleteSubscriptionsRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().deleteSubscriptions(request); + + session.getSessionDiagnostics().getDeleteSubscriptionsCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onTransferSubscriptions(ServiceRequestContext context, TransferSubscriptionsRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = transferSubscriptions(request, session); + + session.getSessionDiagnostics().getTransferSubscriptionsCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onSetPublishingMode(ServiceRequestContext context, SetPublishingModeRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().setPublishingMode(request); + + session.getSessionDiagnostics().getSetPublishingModeCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onPublish(ServiceRequestContext context, PublishRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().publish(context, request); + + session.getSessionDiagnostics().getPublishCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onRepublish(ServiceRequestContext context, RepublishRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = + session.getSubscriptionManager().republish(request); + + session.getSessionDiagnostics().getRepublishCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + private CompletableFuture transferSubscriptions( + TransferSubscriptionsRequest request, + Session session + ) { + + List subscriptionIds = List.of(request.getSubscriptionIds()); + + if (subscriptionIds.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + var results = new ArrayList(); + + for (UInteger subscriptionId : subscriptionIds) { + Subscription subscription = server.getSubscriptions().get(subscriptionId); + + if (subscription == null) { + results.add(new TransferResult( + new StatusCode(StatusCodes.Bad_SubscriptionIdInvalid), + new UInteger[0] + )); + } else { + Session otherSession = subscription.getSession(); + + if (!sessionsHaveSameUser(session, otherSession)) { + results.add(new TransferResult( + new StatusCode(StatusCodes.Bad_UserAccessDenied), + new UInteger[0] + )); + } else { + UInteger[] availableSequenceNumbers; + + synchronized (subscription) { + otherSession.getSubscriptionManager().sendStatusChangeNotification( + subscription, + new StatusCode(StatusCodes.Good_SubscriptionTransferred) + ); + otherSession.getSubscriptionManager().removeSubscription(subscriptionId); + + subscription.setSubscriptionManager(session.getSubscriptionManager()); + session.getSubscriptionManager().addSubscription(subscription); + + subscription.getMonitoredItems().values().forEach(item -> item.setSession(session)); + + availableSequenceNumbers = subscription.getAvailableSequenceNumbers(); + + if (request.getSendInitialValues()) { + subscription.getMonitoredItems().values().stream() + .filter(item -> item instanceof MonitoredDataItem) + .map(item -> (MonitoredDataItem) item) + .forEach(MonitoredDataItem::maybeSendLastValue); + } + } + + subscription.getSubscriptionDiagnostics().getTransferRequestCount().increment(); + + ApplicationDescription toClient = session.getClientDescription(); + ApplicationDescription fromClient = otherSession.getClientDescription(); + + if (Objects.equals(toClient, fromClient)) { + subscription.getSubscriptionDiagnostics().getTransferredToSameClientCount().increment(); + } else { + subscription.getSubscriptionDiagnostics().getTransferredToAltClientCount().increment(); + } + + results.add(new TransferResult(StatusCode.GOOD, availableSequenceNumbers)); + } + } + } + + var response = new TransferSubscriptionsResponse( + createResponseHeader(request), + results.toArray(TransferResult[]::new), + new DiagnosticInfo[0] + ); + + return CompletableFuture.completedFuture(response); + } + + private static boolean sessionsHaveSameUser(Session s1, Session s2) { + Object identity1 = s1.getIdentityObject(); + Object identity2 = s2.getIdentityObject(); + + return Objects.equals(identity1, identity2); + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultViewServiceSet.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultViewServiceSet.java new file mode 100644 index 000000000..afffa3bf7 --- /dev/null +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/DefaultViewServiceSet.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.sdk.server.services.impl; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + +import org.eclipse.milo.opcua.sdk.server.OpcUaServer; +import org.eclipse.milo.opcua.sdk.server.Session; +import org.eclipse.milo.opcua.sdk.server.api.services.ViewServices.RegisterNodesContext; +import org.eclipse.milo.opcua.sdk.server.api.services.ViewServices.UnregisterNodesContext; +import org.eclipse.milo.opcua.sdk.server.services.ViewServiceSet; +import org.eclipse.milo.opcua.sdk.server.services.impl.helpers.BrowseHelper; +import org.eclipse.milo.opcua.sdk.server.services.impl.helpers.BrowsePathsHelper; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResult; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; +import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesResponse; +import org.eclipse.milo.opcua.stack.core.util.FutureUtils; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; + +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; +import static org.eclipse.milo.opcua.stack.core.util.FutureUtils.failedUaFuture; + +public class DefaultViewServiceSet implements ViewServiceSet { + + private final BrowseHelper browseHelper; + + private final OpcUaServer server; + + public DefaultViewServiceSet(OpcUaServer server) { + this.server = server; + + browseHelper = new BrowseHelper(server.getConfig().getExecutor()); + } + + @Override + public CompletableFuture onBrowse(ServiceRequestContext context, BrowseRequest request) { + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = browse(request, session); + + session.getSessionDiagnostics().getBrowseCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onBrowseNext( + ServiceRequestContext context, + BrowseNextRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = browseHelper.browseNext(server, session, request) + .thenApply(results -> { + ResponseHeader header = createResponseHeader(request); + + return new BrowseNextResponse(header, results, new DiagnosticInfo[0]); + }); + + session.getSessionDiagnostics().getBrowseNextCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onTranslateBrowsePaths( + ServiceRequestContext context, + TranslateBrowsePathsToNodeIdsRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + // TODO Session-less service invocation? + return CompletableFuture.failedFuture(e); + } + + var browsePathsHelper = new BrowsePathsHelper(() -> Optional.ofNullable(session), server); + + CompletableFuture future = + browsePathsHelper.translateBrowsePaths(request); + + session.getSessionDiagnostics().getTranslateBrowsePathsToNodeIdsCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onRegisterNodes( + ServiceRequestContext context, + RegisterNodesRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = registerNodes(request, session); + + session.getSessionDiagnostics().getRegisterNodesCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + @Override + public CompletableFuture onUnregisterNodes( + ServiceRequestContext context, + UnregisterNodesRequest request + ) { + + Session session; + try { + session = server.getSessionManager() + .getSession(context, request.getRequestHeader()); + } catch (UaException e) { + return CompletableFuture.failedFuture(e); + } + + CompletableFuture future = unregisterNodes(request, session); + + session.getSessionDiagnostics().getUnregisterNodesCount().record(future); + session.getSessionDiagnostics().getTotalRequestCount().record(future); + + return future; + } + + private CompletableFuture browse(BrowseRequest request, Session session) { + List nodesToBrowse = List.of(request.getNodesToBrowse()); + + if (nodesToBrowse.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (nodesToBrowse.size() > server.getConfig().getLimits().getMaxNodesPerBrowse().intValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + if (request.getView().getViewId().isNotNull() && + !server.getRegisteredViews().contains(request.getView().getViewId())) { + + return failedUaFuture(StatusCodes.Bad_ViewIdUnknown); + } + + Stream> futures = nodesToBrowse.stream().map( + browseDescription -> + browseHelper.browse( + () -> Optional.of(session), + server, + request.getView(), + request.getRequestedMaxReferencesPerNode(), + browseDescription + ) + ); + + return FutureUtils.sequence(futures).thenApply(results -> { + ResponseHeader header = createResponseHeader(request); + + return new BrowseResponse(header, results.toArray(BrowseResult[]::new), new DiagnosticInfo[0]); + }); + } + + private CompletableFuture registerNodes(RegisterNodesRequest request, Session session) { + List nodeIds = List.of(request.getNodesToRegister()); + + if (nodeIds.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (nodeIds.size() > server.getConfig().getLimits().getMaxNodesPerRegisterNodes().intValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + var registerNodesContext = new RegisterNodesContext(server, session); + + server.getAddressSpaceManager().registerNodes(registerNodesContext, nodeIds); + + return registerNodesContext.getFuture().thenApply(registeredNodeIds -> { + ResponseHeader header = createResponseHeader(request); + + return new RegisterNodesResponse(header, registeredNodeIds.toArray(new NodeId[0])); + }); + } + + private CompletableFuture unregisterNodes(UnregisterNodesRequest request, Session session) { + List nodeIds = List.of(request.getNodesToUnregister()); + + if (nodeIds.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + + if (nodeIds.size() > server.getConfig().getLimits().getMaxNodesPerRegisterNodes().intValue()) { + return failedUaFuture(StatusCodes.Bad_TooManyOperations); + } + + var unregisterNodesContext = new UnregisterNodesContext(server, session); + + server.getAddressSpaceManager().unregisterNodes(unregisterNodesContext, nodeIds); + + return unregisterNodesContext.getFuture().thenApply(registeredNodeIds -> { + ResponseHeader header = createResponseHeader(request); + + return new UnregisterNodesResponse(header); + }); + } + +} diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/helpers/BrowseHelper.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/helpers/BrowseHelper.java similarity index 91% rename from opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/helpers/BrowseHelper.java rename to opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/helpers/BrowseHelper.java index 27b8783fa..0c25a0cf1 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/helpers/BrowseHelper.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/helpers/BrowseHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.sdk.server.services.helpers; +package org.eclipse.milo.opcua.sdk.server.services.impl.helpers; import java.util.ArrayList; import java.util.Collections; @@ -25,13 +25,11 @@ import org.eclipse.milo.opcua.sdk.server.api.AccessContext; import org.eclipse.milo.opcua.sdk.server.api.services.AttributeServices.ReadContext; import org.eclipse.milo.opcua.sdk.server.api.services.ViewServices.BrowseContext; -import org.eclipse.milo.opcua.sdk.server.services.ServiceAttributes; import org.eclipse.milo.opcua.stack.core.AttributeId; import org.eclipse.milo.opcua.stack.core.NodeIds; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; -import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; @@ -43,23 +41,20 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; import org.eclipse.milo.opcua.stack.core.types.structured.BrowseDescription; import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextResponse; import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResult; import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; import org.eclipse.milo.opcua.stack.core.types.structured.ViewDescription; import org.eclipse.milo.opcua.stack.core.util.ExecutionQueue; import org.eclipse.milo.opcua.stack.core.util.FutureUtils; import org.eclipse.milo.opcua.stack.core.util.NonceUtil; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; import org.slf4j.LoggerFactory; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.stream.Collectors.toList; import static org.eclipse.milo.opcua.sdk.server.util.UaEnumUtil.browseResultMasks; import static org.eclipse.milo.opcua.sdk.server.util.UaEnumUtil.nodeClasses; -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; +import static org.eclipse.milo.opcua.stack.core.util.FutureUtils.failedUaFuture; public class BrowseHelper { @@ -119,20 +114,13 @@ public CompletableFuture browse( } } - public void browseNext(ServiceRequest service) { - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); - - BrowseNextRequest request = (BrowseNextRequest) service.getRequest(); - - List continuationPoints = l(request.getContinuationPoints()); - - if (continuationPoints.size() > - server.getConfig().getLimits().getMaxBrowseContinuationPoints().intValue()) { + public CompletableFuture browseNext( + OpcUaServer server, + Session session, + BrowseNextRequest request + ) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - } else { - server.getExecutorService().execute(new BrowseNext(server, service)); - } + return new BrowseNext2(server, session, request).browseNext(); } private class Browse { @@ -428,29 +416,29 @@ private CompletableFuture getTypeDefinition(NodeId nodeId) { } - private static class BrowseNext implements Runnable { + private static class BrowseNext2 { + private final OpcUaServer server; private final Session session; + private final BrowseNextRequest request; - private final OpcUaServer server; - private final ServiceRequest service; - private BrowseNext(OpcUaServer server, ServiceRequest service) { + private BrowseNext2(OpcUaServer server, Session session, BrowseNextRequest request) { this.server = server; - this.service = service; - - session = service.attr(ServiceAttributes.SESSION_KEY).get(); + this.session = session; + this.request = request; } - @Override - public void run() { - BrowseNextRequest request = (BrowseNextRequest) service.getRequest(); - - List continuationPoints = l(request.getContinuationPoints()); + public CompletableFuture browseNext() { + List continuationPoints = List.of(request.getContinuationPoints()); if (continuationPoints.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } + if (continuationPoints.size() > + server.getConfig().getLimits().getMaxBrowseContinuationPoints().intValue()) { + + return failedUaFuture(StatusCodes.Bad_TooManyOperations); } var results = new ArrayList(); @@ -463,15 +451,7 @@ public void run() { } } - ResponseHeader header = service.createResponseHeader(); - - BrowseNextResponse response = new BrowseNextResponse( - header, - results.toArray(new BrowseResult[0]), - new DiagnosticInfo[0] - ); - - service.setResponse(response); + return CompletableFuture.completedFuture(results.toArray(BrowseResult[]::new)); } private BrowseResult release(ByteString bs) { @@ -505,7 +485,8 @@ private BrowseResult references(ByteString bs) { return new BrowseResult( StatusCode.GOOD, null, - references.toArray(new ReferenceDescription[0])); + references.toArray(new ReferenceDescription[0]) + ); } } else { return new BrowseResult(BAD_CONTINUATION_POINT_INVALID, null, null); diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/helpers/BrowsePathsHelper.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/helpers/BrowsePathsHelper.java similarity index 92% rename from opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/helpers/BrowsePathsHelper.java rename to opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/helpers/BrowsePathsHelper.java index a5438407d..23cadcf57 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/helpers/BrowsePathsHelper.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/services/impl/helpers/BrowsePathsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.sdk.server.services.helpers; +package org.eclipse.milo.opcua.sdk.server.services.impl.helpers; import java.util.ArrayList; import java.util.Collections; @@ -21,7 +21,6 @@ import org.eclipse.milo.opcua.sdk.server.api.AccessContext; import org.eclipse.milo.opcua.sdk.server.api.services.AttributeServices.ReadContext; import org.eclipse.milo.opcua.sdk.server.api.services.ViewServices.BrowseContext; -import org.eclipse.milo.opcua.sdk.server.services.ServiceAttributes; import org.eclipse.milo.opcua.stack.core.AttributeId; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; @@ -42,10 +41,10 @@ import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsRequest; import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsResponse; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.stream.Collectors.toList; +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; @@ -62,23 +61,19 @@ public BrowsePathsHelper(AccessContext context, OpcUaServer server) { this.server = server; } - public void onTranslateBrowsePaths(ServiceRequest service) { - TranslateBrowsePathsToNodeIdsRequest request = (TranslateBrowsePathsToNodeIdsRequest) service.getRequest(); - - OpcUaServer server = service.attr(ServiceAttributes.SERVER_KEY).get(); + public CompletableFuture translateBrowsePaths( + TranslateBrowsePathsToNodeIdsRequest request + ) { - List browsePaths = l(request.getBrowsePaths()); + List browsePaths = List.of(request.getBrowsePaths()); if (browsePaths.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; + return failedUaFuture(StatusCodes.Bad_NothingToDo); } - if (browsePaths.size() > server.getConfig().getLimits().getMaxNodesPerTranslateBrowsePathsToNodeIds().intValue()) { - service.setServiceFault(StatusCodes.Bad_TooManyOperations); - return; + return failedUaFuture(StatusCodes.Bad_TooManyOperations); } var futures = new ArrayList>(browsePaths.size()); @@ -87,16 +82,16 @@ public void onTranslateBrowsePaths(ServiceRequest service) { futures.add(translate(browsePath)); } - sequence(futures).thenAcceptAsync(results -> { - ResponseHeader header = service.createResponseHeader(); + return sequence(futures).thenComposeAsync(results -> { + ResponseHeader header = createResponseHeader(request); - TranslateBrowsePathsToNodeIdsResponse response = new TranslateBrowsePathsToNodeIdsResponse( + var response = new TranslateBrowsePathsToNodeIdsResponse( header, - a(results, BrowsePathResult.class), + results.toArray(BrowsePathResult[]::new), new DiagnosticInfo[0] ); - service.setResponse(response); + return CompletableFuture.completedFuture(response); }, server.getExecutorService()); } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/PublishQueue.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/PublishQueue.java index 2dd845537..a11453401 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/PublishQueue.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/PublishQueue.java @@ -14,12 +14,18 @@ import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse; import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,28 +34,26 @@ public class PublishQueue { private final Logger logger = LoggerFactory.getLogger(getClass()); - private final LinkedList serviceQueue = new LinkedList<>(); + private final LinkedList pendingQueue = new LinkedList<>(); private final LinkedHashMap waitList = new LinkedHashMap<>(); - /** - * Add a Publish {@link ServiceRequest} to the queue. - *

- * If there are wait-listed Subscriptions this request will be used immediately, otherwise it will be queued for - * later use by a Subscription whose publish timer has expired and has notifications to send. - * - * @param service the Publish {@link ServiceRequest}. - */ - public synchronized void addRequest(ServiceRequest service) { + private final ExecutorService executor; + + public PublishQueue(ExecutorService executor) { + this.executor = executor; + } + + public synchronized void addRequest(PendingPublish pending) { List waitingSubscriptions = List.copyOf(waitList.values()); if (waitingSubscriptions.isEmpty()) { - serviceQueue.add(service); + pendingQueue.add(pending); logger.debug( "Queued PublishRequest requestHandle={}, size={}", - service.getRequest().getRequestHeader().getRequestHandle(), - serviceQueue.size() + pending.request.getRequestHeader().getRequestHandle(), + pendingQueue.size() ); } else { logger.debug("{} subscriptions waiting", waitingSubscriptions.size()); @@ -97,11 +101,9 @@ public synchronized void addRequest(ServiceRequest service) { final WaitingSubscription ws = subscription; - service.getServer().getConfig().getExecutor().execute( - () -> ws.subscription.onPublish(service) - ); + executor.execute(() -> ws.subscription.onPublish(pending)); } else { - serviceQueue.add(service); + pendingQueue.add(pending); } } } @@ -120,14 +122,11 @@ public synchronized void addRequest(ServiceRequest service) { * @param subscription the subscription to wait-list. */ public synchronized void addSubscription(Subscription subscription) { - if (waitList.isEmpty() && !serviceQueue.isEmpty()) { - ServiceRequest request = poll(); + if (waitList.isEmpty() && !pendingQueue.isEmpty()) { + PendingPublish pending = poll(); - if (request != null) { - request.getServer().getConfig().getExecutor().execute( - () -> - subscription.onPublish(request) - ); + if (pending != null) { + executor.execute(() -> subscription.onPublish(pending)); } else { waitList.putIfAbsent(subscription.getId(), new WaitingSubscription(subscription)); } @@ -137,7 +136,7 @@ public synchronized void addSubscription(Subscription subscription) { } public synchronized boolean isEmpty() { - return serviceQueue.isEmpty(); + return pendingQueue.isEmpty(); } public synchronized boolean isNotEmpty() { @@ -148,38 +147,35 @@ public synchronized boolean isWaitListEmpty() { return waitList.isEmpty(); } - @Nullable - public synchronized ServiceRequest poll() { + public synchronized @Nullable PublishQueue.PendingPublish poll() { long nowNanos = System.nanoTime(); while (true) { - ServiceRequest serviceRequest = serviceQueue.poll(); + PendingPublish pending = pendingQueue.poll(); - if (serviceRequest == null) { + if (pending == null) { return null; } else { - RequestHeader requestHeader = serviceRequest - .getRequest() - .getRequestHeader(); + RequestHeader requestHeader = pending.request.getRequestHeader(); long millisSinceReceived = TimeUnit.MILLISECONDS.convert( - nowNanos - serviceRequest.getReceivedAtNanos(), + nowNanos - pending.context.receivedAtNanos(), TimeUnit.NANOSECONDS ); long timeoutHint = requestHeader.getTimeoutHint().longValue(); if (timeoutHint == 0 || millisSinceReceived < timeoutHint) { - return serviceRequest; + return pending; } else { logger.debug( "Discarding expired PublishRequest requestHandle={} timestamp={} timeoutHint={}", - serviceRequest.getRequest().getRequestHeader().getRequestHandle(), + pending.request.getRequestHeader().getRequestHandle(), requestHeader.getTimestamp().getJavaDate(), timeoutHint ); - serviceRequest.setServiceFault(StatusCodes.Bad_Timeout); + pending.responseFuture.completeExceptionally(new UaException(StatusCodes.Bad_Timeout)); } } } @@ -191,7 +187,28 @@ public synchronized ServiceRequest poll() { * @return the number of queued Publish ServiceRequests. */ public synchronized int size() { - return serviceQueue.size(); + return pendingQueue.size(); + } + + public static class PendingPublish { + + public final CompletableFuture responseFuture = new CompletableFuture<>(); + + public final ServiceRequestContext context; + public final PublishRequest request; + public final StatusCode[] acknowledgeResults; + + public PendingPublish( + ServiceRequestContext context, + PublishRequest request, + StatusCode[] acknowledgeResults + ) { + + this.context = context; + this.request = request; + this.acknowledgeResults = acknowledgeResults; + } + } public static class WaitingSubscription { diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/Subscription.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/Subscription.java index 311532960..fe082a1af 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/Subscription.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/Subscription.java @@ -34,6 +34,7 @@ import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfigLimits; import org.eclipse.milo.opcua.sdk.server.diagnostics.SubscriptionDiagnostics; import org.eclipse.milo.opcua.sdk.server.items.BaseMonitoredItem; +import org.eclipse.milo.opcua.sdk.server.subscriptions.PublishQueue.PendingPublish; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaDefaultBinaryEncoding; @@ -55,11 +56,10 @@ import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; import org.eclipse.milo.opcua.stack.core.types.structured.SetPublishingModeRequest; import org.eclipse.milo.opcua.stack.core.types.structured.StatusChangeNotification; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.eclipse.milo.opcua.sdk.server.subscriptions.SubscriptionManager.KEY_ACK_RESULTS; +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; public class Subscription { @@ -362,8 +362,8 @@ private void resetKeepAliveCounter() { logger.debug("[id={}] keep-alive counter reset to {}", subscriptionId, maxKeepAliveCount); } - private void returnKeepAlive(ServiceRequest service) { - ResponseHeader header = service.createResponseHeader(); + private void returnKeepAlive(PendingPublish pending) { + ResponseHeader header = createResponseHeader(pending.request); UInteger sequenceNumber = uint(currentSequenceNumber()); @@ -375,7 +375,7 @@ private void returnKeepAlive(ServiceRequest service) { UInteger[] available = getAvailableSequenceNumbers(); - StatusCode[] acknowledgeResults = service.attr(KEY_ACK_RESULTS).get(); + StatusCode[] acknowledgeResults = pending.acknowledgeResults; PublishResponse response = new PublishResponse( header, @@ -387,13 +387,15 @@ private void returnKeepAlive(ServiceRequest service) { new DiagnosticInfo[0] ); - service.setResponse(response); + pending.responseFuture.complete(response); - logger.debug("[id={}] returned keep-alive NotificationMessage sequenceNumber={}.", - subscriptionId, sequenceNumber); + logger.debug( + "[id={}] returned keep-alive NotificationMessage sequenceNumber={}.", + subscriptionId, sequenceNumber + ); } - void returnStatusChangeNotification(ServiceRequest service, StatusCode status) { + void publishStatusChangeNotification(PendingPublish pending, StatusCode status) { StatusChangeNotification statusChange = new StatusChangeNotification(status, null); UInteger sequenceNumber = uint(nextSequenceNumber()); @@ -404,7 +406,7 @@ void returnStatusChangeNotification(ServiceRequest service, StatusCode status) { new ExtensionObject[]{ExtensionObject.encode(encodingContext, statusChange)} ); - ResponseHeader header = service.createResponseHeader(); + ResponseHeader header = createResponseHeader(pending.request); PublishResponse response = new PublishResponse( header, @@ -412,11 +414,11 @@ void returnStatusChangeNotification(ServiceRequest service, StatusCode status) { new UInteger[0], false, notificationMessage, - service.attr(KEY_ACK_RESULTS).get(), + pending.acknowledgeResults, new DiagnosticInfo[0] ); - service.setResponse(response); + pending.responseFuture.complete(response); logger.debug( "[id={}] returned StatusChangeNotification ({}) sequenceNumber={}.", @@ -426,7 +428,7 @@ void returnStatusChangeNotification(ServiceRequest service, StatusCode status) { ); } - private void returnNotifications(ServiceRequest service) { + private void returnNotifications(PendingPublish pending) { LinkedHashSet> items = new LinkedHashSet<>(); lastIterator.forEachRemaining(items::add); @@ -437,7 +439,7 @@ private void returnNotifications(ServiceRequest service) { PeekingIterator> iterator = Iterators.peekingIterator(items.iterator()); - gatherAndSend(iterator, service); + gatherAndSend(iterator, pending); lastIterator = iterator.hasNext() ? iterator : Collections.emptyIterator(); } @@ -446,12 +448,9 @@ private void returnNotifications(ServiceRequest service) { * Gather {@link MonitoredItemNotification}s and send them using {@code service}. * * @param iterator a {@link PeekingIterator} over the current {@link BaseMonitoredItem}s. - * @param service a {@link ServiceRequest}. + * @param pending a {@link PendingPublish}. */ - private void gatherAndSend( - PeekingIterator> iterator, - ServiceRequest service) { - + private void gatherAndSend(PeekingIterator> iterator, PendingPublish pending) { var notifications = new ArrayList(); while (notifications.size() < maxNotificationsPerPublish && iterator.hasNext()) { @@ -471,13 +470,13 @@ private void gatherAndSend( moreNotifications = iterator.hasNext(); - sendNotifications(service, notifications); + sendNotifications(pending, notifications); if (moreNotifications) { - ServiceRequest nextService = publishQueue().poll(); + PendingPublish next = publishQueue().poll(); - if (nextService != null) { - gatherAndSend(iterator, nextService); + if (next != null) { + gatherAndSend(iterator, next); } else { publishQueue().addSubscription(this); } @@ -490,7 +489,7 @@ private boolean gather(BaseMonitoredItem item, List notific return item.getNotifications(notifications, max); } - private void sendNotifications(ServiceRequest service, List notifications) { + private void sendNotifications(PendingPublish pending, List notifications) { var dataNotifications = new ArrayList(); var eventNotifications = new ArrayList(); @@ -556,9 +555,9 @@ private void sendNotifications(ServiceRequest service, List no } UInteger[] available = getAvailableSequenceNumbers(); - StatusCode[] acknowledgeResults = service.attr(KEY_ACK_RESULTS).get(); + StatusCode[] acknowledgeResults = pending.acknowledgeResults; - ResponseHeader header = service.createResponseHeader(); + ResponseHeader header = createResponseHeader(pending.request); PublishResponse response = new PublishResponse( header, @@ -570,13 +569,14 @@ private void sendNotifications(ServiceRequest service, List no new DiagnosticInfo[0] ); - service.setResponse(response); + pending.responseFuture.complete(response); logger.debug( "[id={}] returning {} DataChangeNotification(s) and " + "{} EventNotificationList(s) sequenceNumber={} moreNotifications={}.", subscriptionId, dataNotifications.size(), - eventNotifications.size(), sequenceNumber, moreNotifications); + eventNotifications.size(), sequenceNumber, moreNotifications + ); } private boolean notificationsAvailable() { @@ -701,9 +701,9 @@ public void setStateListener(StateListener listener) { /** * Handle an incoming {@link PublishRequest}. * - * @param service The service request that contains the {@link PublishRequest}. + * @param pending The service request that contains the {@link PublishRequest}. */ - synchronized void onPublish(ServiceRequest service) { + synchronized void onPublish(PendingPublish pending) { State state = this.state.get(); if (logger.isTraceEnabled()) { @@ -712,15 +712,15 @@ synchronized void onPublish(ServiceRequest service) { } if (state == State.Normal) { - publishHandler.whenNormal(service); + publishHandler.whenNormal(pending); } else if (state == State.KeepAlive) { - publishHandler.whenKeepAlive(service); + publishHandler.whenKeepAlive(pending); } else if (state == State.Late) { - publishHandler.whenLate(service); + publishHandler.whenLate(pending); } else if (state == State.Closing) { - publishHandler.whenClosing(service); + publishHandler.whenClosing(pending); } else if (state == State.Closed) { - publishHandler.whenClosed(service); + publishHandler.whenClosed(pending); } else { throw new RuntimeException("Unhandled subscription state: " + state); } @@ -828,12 +828,12 @@ public SubscriptionDiagnostics getSubscriptionDiagnostics() { } private class PublishHandler { - private void whenNormal(ServiceRequest service) { + private void whenNormal(PendingPublish pending) { boolean publishingEnabled = Subscription.this.publishingEnabled; if (!publishingEnabled || (publishingEnabled && !moreNotifications)) { /* Subscription State Table Row 4 */ - publishQueue().addRequest(service); + publishQueue().addRequest(pending); } else if (publishingEnabled && moreNotifications) { subscriptionDiagnostics.getPublishRequestCount().increment(); @@ -841,13 +841,13 @@ private void whenNormal(ServiceRequest service) { resetLifetimeCounter(); resetKeepAliveCounter(); messageSent = true; - returnNotifications(service); + returnNotifications(pending); } else { throw new IllegalStateException("unhandled subscription state"); } } - private void whenLate(ServiceRequest service) { + private void whenLate(PendingPublish pending) { boolean publishingEnabled = Subscription.this.publishingEnabled; boolean notificationsAvailable = notificationsAvailable(); @@ -859,7 +859,7 @@ private void whenLate(ServiceRequest service) { resetLifetimeCounter(); resetKeepAliveCounter(); messageSent = true; - returnNotifications(service); + returnNotifications(pending); } else if (!publishingEnabled || (publishingEnabled && !notificationsAvailable && !moreNotifications)) { subscriptionDiagnostics.getPublishRequestCount().increment(); @@ -869,27 +869,27 @@ private void whenLate(ServiceRequest service) { resetLifetimeCounter(); resetKeepAliveCounter(); messageSent = true; - returnKeepAlive(service); + returnKeepAlive(pending); } else { throw new IllegalStateException("unhandled subscription state"); } } - private void whenKeepAlive(ServiceRequest service) { + private void whenKeepAlive(PendingPublish pending) { /* Subscription State Table Row 13 */ - publishQueue().addRequest(service); + publishQueue().addRequest(pending); } - private void whenClosing(ServiceRequest service) { + private void whenClosing(PendingPublish pending) { subscriptionDiagnostics.getPublishRequestCount().increment(); - returnStatusChangeNotification(service, new StatusCode(StatusCodes.Bad_Timeout)); + publishStatusChangeNotification(pending, new StatusCode(StatusCodes.Bad_Timeout)); setState(State.Closed); } - private void whenClosed(ServiceRequest service) { - publishQueue().addRequest(service); + private void whenClosed(PendingPublish pending) { + publishQueue().addRequest(pending); } } @@ -901,30 +901,30 @@ private void whenNormal() { if (publishRequestQueued && publishingEnabled && notificationsAvailable) { /* Subscription State Table Row 6 */ - ServiceRequest service = publishQueue().poll(); + PendingPublish pending = publishQueue().poll(); - if (service != null) { + if (pending != null) { subscriptionDiagnostics.getPublishRequestCount().increment(); resetLifetimeCounter(); resetKeepAliveCounter(); messageSent = true; - returnNotifications(service); + returnNotifications(pending); } else { whenNormal(); } } else if (publishRequestQueued && !messageSent && (!publishingEnabled || (publishingEnabled && !notificationsAvailable))) { /* Subscription State Table Row 7 */ - ServiceRequest service = publishQueue().poll(); + PendingPublish pending = publishQueue().poll(); - if (service != null) { + if (pending != null) { subscriptionDiagnostics.getPublishRequestCount().increment(); resetLifetimeCounter(); resetKeepAliveCounter(); messageSent = true; - returnKeepAlive(service); + returnKeepAlive(pending); } else { whenNormal(); } @@ -959,16 +959,16 @@ private void whenKeepAlive() { if (publishingEnabled && notificationsAvailable && publishRequestQueued) { /* Subscription State Table Row 14 */ - ServiceRequest service = publishQueue().poll(); + PendingPublish pending = publishQueue().poll(); - if (service != null) { + if (pending != null) { subscriptionDiagnostics.getPublishRequestCount().increment(); setState(State.Normal); resetLifetimeCounter(); resetKeepAliveCounter(); messageSent = true; - returnNotifications(service); + returnNotifications(pending); } else { whenKeepAlive(); } @@ -976,14 +976,15 @@ private void whenKeepAlive() { (!publishingEnabled || (publishingEnabled && !notificationsAvailable))) { /* Subscription State Table Row 15 */ - ServiceRequest service = publishQueue().poll(); - if (service != null) { + PendingPublish pending = publishQueue().poll(); + + if (pending != null) { subscriptionDiagnostics.getPublishRequestCount().increment(); resetLifetimeCounter(); resetKeepAliveCounter(); - returnKeepAlive(service); + returnKeepAlive(pending); } else { whenKeepAlive(); } diff --git a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/SubscriptionManager.java b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/SubscriptionManager.java index ec7f722a4..542b3e7de 100644 --- a/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/SubscriptionManager.java +++ b/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/subscriptions/SubscriptionManager.java @@ -40,6 +40,7 @@ import org.eclipse.milo.opcua.sdk.server.items.MonitoredDataItem; import org.eclipse.milo.opcua.sdk.server.items.MonitoredEventItem; import org.eclipse.milo.opcua.sdk.server.nodes.UaNode; +import org.eclipse.milo.opcua.sdk.server.subscriptions.PublishQueue.PendingPublish; import org.eclipse.milo.opcua.sdk.server.subscriptions.Subscription.State; import org.eclipse.milo.opcua.stack.core.AttributeId; import org.eclipse.milo.opcua.stack.core.NodeIds; @@ -79,6 +80,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters; import org.eclipse.milo.opcua.stack.core.types.structured.NotificationMessage; import org.eclipse.milo.opcua.stack.core.types.structured.PublishRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.PublishResponse; import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; import org.eclipse.milo.opcua.stack.core.types.structured.RepublishRequest; import org.eclipse.milo.opcua.stack.core.types.structured.RepublishResponse; @@ -90,16 +92,18 @@ import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringRequest; import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringResponse; import org.eclipse.milo.opcua.stack.core.types.structured.SubscriptionAcknowledgement; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static java.util.stream.Collectors.toList; import static org.eclipse.milo.opcua.sdk.core.util.StreamUtil.opt2stream; +import static org.eclipse.milo.opcua.sdk.server.services.AbstractServiceSet.createResponseHeader; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ubyte; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; +import static org.eclipse.milo.opcua.stack.core.util.FutureUtils.failedUaFuture; public class SubscriptionManager { @@ -113,19 +117,22 @@ private static UInteger nextSubscriptionId() { private final Logger logger = LoggerFactory.getLogger(getClass()); - private final PublishQueue publishQueue = new PublishQueue(); private final Map subscriptions = new ConcurrentHashMap<>(); private final List transferred = new CopyOnWriteArrayList<>(); private final AtomicLong monitoredItemCount = new AtomicLong(0L); + private final PublishQueue publishQueue; + private final Session session; private final OpcUaServer server; public SubscriptionManager(Session session, OpcUaServer server) { this.session = session; this.server = server; + + publishQueue = new PublishQueue(server.getConfig().getExecutor()); } public Session getSession() { @@ -149,22 +156,18 @@ public List getSubscriptions() { return new ArrayList<>(subscriptions.values()); } - public void createSubscription(ServiceRequest service) { - CreateSubscriptionRequest request = (CreateSubscriptionRequest) service.getRequest(); - + public CompletableFuture createSubscription(CreateSubscriptionRequest request) { if (subscriptions.size() >= server.getConfig().getLimits().getMaxSubscriptionsPerSession().intValue()) { - service.setServiceFault(StatusCodes.Bad_TooManySubscriptions); - return; + return failedUaFuture(StatusCodes.Bad_TooManySubscriptions); } if (server.getSubscriptions().size() >= server.getConfig().getLimits().getMaxSubscriptions().intValue()) { - service.setServiceFault(StatusCodes.Bad_TooManySubscriptions); - return; + return failedUaFuture(StatusCodes.Bad_TooManySubscriptions); } UInteger subscriptionId = nextSubscriptionId(); - Subscription subscription = new Subscription( + var subscription = new Subscription( this, subscriptionId, request.getRequestedPublishingInterval(), @@ -207,9 +210,9 @@ public void createSubscription(ServiceRequest service) { subscription.startPublishingTimer(); - ResponseHeader header = service.createResponseHeader(); + ResponseHeader header = createResponseHeader(request); - CreateSubscriptionResponse response = new CreateSubscriptionResponse( + var response = new CreateSubscriptionResponse( header, subscriptionId, subscription.getPublishingInterval(), @@ -217,40 +220,36 @@ public void createSubscription(ServiceRequest service) { uint(subscription.getMaxKeepAliveCount()) ); - service.setResponse(response); + return CompletableFuture.completedFuture(response); } - public void modifySubscription(ServiceRequest service) throws UaException { - ModifySubscriptionRequest request = (ModifySubscriptionRequest) service.getRequest(); - + public CompletableFuture modifySubscription(ModifySubscriptionRequest request) { UInteger subscriptionId = request.getSubscriptionId(); Subscription subscription = subscriptions.get(subscriptionId); if (subscription == null) { - throw new UaException(StatusCodes.Bad_SubscriptionIdInvalid); + return failedUaFuture(StatusCodes.Bad_SubscriptionIdInvalid); } subscription.modifySubscription(request); - ResponseHeader header = service.createResponseHeader(); + ResponseHeader header = createResponseHeader(request); - ModifySubscriptionResponse response = new ModifySubscriptionResponse( + var response = new ModifySubscriptionResponse( header, subscription.getPublishingInterval(), uint(subscription.getLifetimeCount()), uint(subscription.getMaxKeepAliveCount()) ); - service.setResponse(response); + return CompletableFuture.completedFuture(response); } - public void deleteSubscription(ServiceRequest service) throws UaException { - DeleteSubscriptionsRequest request = (DeleteSubscriptionsRequest) service.getRequest(); - + public CompletableFuture deleteSubscriptions(DeleteSubscriptionsRequest request) { List subscriptionIds = l(request.getSubscriptionIds()); if (subscriptionIds.isEmpty()) { - throw new UaException(StatusCodes.Bad_NothingToDo); + return failedUaFuture(StatusCodes.Bad_NothingToDo); } StatusCode[] results = new StatusCode[subscriptionIds.size()]; @@ -284,26 +283,27 @@ public void deleteSubscription(ServiceRequest service) throws UaException { } } - ResponseHeader header = service.createResponseHeader(); + ResponseHeader header = createResponseHeader(request); - DeleteSubscriptionsResponse response = new DeleteSubscriptionsResponse( + var response = new DeleteSubscriptionsResponse( header, results, new DiagnosticInfo[0] ); - service.setResponse(response); - while (subscriptions.isEmpty() && publishQueue.isNotEmpty()) { - ServiceRequest publishService = publishQueue.poll(); - if (publishService != null) { - publishService.setServiceFault(StatusCodes.Bad_NoSubscription); + PendingPublish pending = publishQueue.poll(); + if (pending != null) { + pending.responseFuture.completeExceptionally( + new UaException(StatusCodes.Bad_NoSubscription) + ); } } + + return CompletableFuture.completedFuture(response); } - public void setPublishingMode(ServiceRequest service) { - SetPublishingModeRequest request = (SetPublishingModeRequest) service.getRequest(); + public CompletableFuture setPublishingMode(SetPublishingModeRequest request) { List subscriptionIds = l(request.getSubscriptionIds()); StatusCode[] results = new StatusCode[subscriptionIds.size()]; @@ -318,33 +318,35 @@ public void setPublishingMode(ServiceRequest service) { } } - ResponseHeader header = service.createResponseHeader(); + ResponseHeader header = createResponseHeader(request); - SetPublishingModeResponse response = new SetPublishingModeResponse( + var response = new SetPublishingModeResponse( header, results, new DiagnosticInfo[0] ); - service.setResponse(response); + return CompletableFuture.completedFuture(response); } - public void createMonitoredItems(ServiceRequest service) throws UaException { - CreateMonitoredItemsRequest request = (CreateMonitoredItemsRequest) service.getRequest(); + public CompletableFuture createMonitoredItems( + ServiceRequestContext context, + CreateMonitoredItemsRequest request + ) { UInteger subscriptionId = request.getSubscriptionId(); Subscription subscription = subscriptions.get(subscriptionId); TimestampsToReturn timestamps = request.getTimestampsToReturn(); - List itemsToCreate = l(request.getItemsToCreate()); + List itemsToCreate = List.of(request.getItemsToCreate()); if (subscription == null) { - throw new UaException(StatusCodes.Bad_SubscriptionIdInvalid); + return failedUaFuture(StatusCodes.Bad_SubscriptionIdInvalid); } if (timestamps == null) { - throw new UaException(StatusCodes.Bad_TimestampsToReturnInvalid); + return failedUaFuture(StatusCodes.Bad_TimestampsToReturnInvalid); } if (itemsToCreate.isEmpty()) { - throw new UaException(StatusCodes.Bad_NothingToDo); + return failedUaFuture(StatusCodes.Bad_NothingToDo); } List distinctNodeIds = itemsToCreate.stream() @@ -354,7 +356,7 @@ public void createMonitoredItems(ServiceRequest service) throws UaException { CompletableFuture> attributesFuture = readMonitoringAttributes(distinctNodeIds); - attributesFuture.thenAccept(attributeGroups -> { + return attributesFuture.thenApply(attributeGroups -> { MonitoredItemCreateResult[] createResults = new MonitoredItemCreateResult[itemsToCreate.size()]; List> monitoredItems = new ArrayList<>(); @@ -416,15 +418,9 @@ public void createMonitoredItems(ServiceRequest service) throws UaException { eventItems -> server.getAddressSpaceManager().onEventItemsCreated(eventItems) ); - ResponseHeader header = service.createResponseHeader(); + ResponseHeader header = createResponseHeader(request); - CreateMonitoredItemsResponse response = new CreateMonitoredItemsResponse( - header, - createResults, - new DiagnosticInfo[0] - ); - - service.setResponse(response); + return new CreateMonitoredItemsResponse(header, createResults, new DiagnosticInfo[0]); }); } @@ -667,22 +663,24 @@ private MonitoringFilter validateEventItemFilter( } } - public void modifyMonitoredItems(ServiceRequest service) throws UaException { - ModifyMonitoredItemsRequest request = (ModifyMonitoredItemsRequest) service.getRequest(); + public CompletableFuture modifyMonitoredItems( + ServiceRequestContext context, + ModifyMonitoredItemsRequest request + ) { UInteger subscriptionId = request.getSubscriptionId(); Subscription subscription = subscriptions.get(subscriptionId); TimestampsToReturn timestamps = request.getTimestampsToReturn(); - List itemsToModify = l(request.getItemsToModify()); + List itemsToModify = List.of(request.getItemsToModify()); if (subscription == null) { - throw new UaException(StatusCodes.Bad_SubscriptionIdInvalid); + return failedUaFuture(StatusCodes.Bad_SubscriptionIdInvalid); } if (timestamps == null) { - throw new UaException(StatusCodes.Bad_TimestampsToReturnInvalid); + return failedUaFuture(StatusCodes.Bad_TimestampsToReturnInvalid); } if (itemsToModify.isEmpty()) { - throw new UaException(StatusCodes.Bad_NothingToDo); + return failedUaFuture(StatusCodes.Bad_NothingToDo); } List distinctNodeIds = itemsToModify.stream() @@ -697,7 +695,7 @@ public void modifyMonitoredItems(ServiceRequest service) throws UaException { CompletableFuture> attributesFuture = readMonitoringAttributes(distinctNodeIds); - attributesFuture.thenAccept(attributeGroups -> { + return attributesFuture.thenApply(attributeGroups -> { MonitoredItemModifyResult[] modifyResults = new MonitoredItemModifyResult[itemsToModify.size()]; List> monitoredItems = new ArrayList<>(); @@ -747,15 +745,13 @@ public void modifyMonitoredItems(ServiceRequest service) throws UaException { * AddressSpaces have been notified; send response. */ - ResponseHeader header = service.createResponseHeader(); + ResponseHeader header = createResponseHeader(request); - ModifyMonitoredItemsResponse response = new ModifyMonitoredItemsResponse( + return new ModifyMonitoredItemsResponse( header, modifyResults, new DiagnosticInfo[0] ); - - service.setResponse(response); }); } @@ -966,22 +962,23 @@ private CompletableFuture> readMonitoringAttributes( }); } - - public void deleteMonitoredItems(ServiceRequest service) throws UaException { - DeleteMonitoredItemsRequest request = (DeleteMonitoredItemsRequest) service.getRequest(); + public CompletableFuture deleteMonitoredItems( + ServiceRequestContext context, + DeleteMonitoredItemsRequest request + ) { UInteger subscriptionId = request.getSubscriptionId(); Subscription subscription = subscriptions.get(subscriptionId); - List itemsToDelete = l(request.getMonitoredItemIds()); + List itemsToDelete = List.of(request.getMonitoredItemIds()); if (subscription == null) { - throw new UaException(StatusCodes.Bad_SubscriptionIdInvalid); + return failedUaFuture(StatusCodes.Bad_SubscriptionIdInvalid); } if (itemsToDelete.isEmpty()) { - throw new UaException(StatusCodes.Bad_NothingToDo); + return failedUaFuture(StatusCodes.Bad_NothingToDo); } - StatusCode[] deleteResults = new StatusCode[itemsToDelete.size()]; + var deleteResults = new StatusCode[itemsToDelete.size()]; var deletedItems = new ArrayList>(itemsToDelete.size()); synchronized (subscription) { @@ -1017,85 +1014,81 @@ public void deleteMonitoredItems(ServiceRequest service) throws UaException { /* * Build and return results. */ - ResponseHeader header = service.createResponseHeader(); - DeleteMonitoredItemsResponse response = new DeleteMonitoredItemsResponse( + ResponseHeader header = createResponseHeader(request); + + var response = new DeleteMonitoredItemsResponse( header, deleteResults, new DiagnosticInfo[0] ); - service.setResponse(response); + return CompletableFuture.completedFuture(response); } - public void setMonitoringMode(ServiceRequest service) { - SetMonitoringModeRequest request = (SetMonitoringModeRequest) service.getRequest(); + public CompletableFuture setMonitoringMode(ServiceRequestContext context, SetMonitoringModeRequest request) { UInteger subscriptionId = request.getSubscriptionId(); + Subscription subscription = subscriptions.get(subscriptionId); + List itemsToModify = List.of(request.getMonitoredItemIds()); - try { - Subscription subscription = subscriptions.get(subscriptionId); - List itemsToModify = l(request.getMonitoredItemIds()); - - if (subscription == null) { - throw new UaException(StatusCodes.Bad_SubscriptionIdInvalid); - } - if (itemsToModify.isEmpty()) { - throw new UaException(StatusCodes.Bad_NothingToDo); - } + if (subscription == null) { + return failedUaFuture(StatusCodes.Bad_SubscriptionIdInvalid); + } + if (itemsToModify.isEmpty()) { + return failedUaFuture(StatusCodes.Bad_NothingToDo); + } - /* - * Set MonitoringMode on each monitored item, if it exists. - */ + /* + * Set MonitoringMode on each monitored item, if it exists. + */ - MonitoringMode monitoringMode = request.getMonitoringMode(); - StatusCode[] results = new StatusCode[itemsToModify.size()]; - var modified = new ArrayList(itemsToModify.size()); + MonitoringMode monitoringMode = request.getMonitoringMode(); + var results = new StatusCode[itemsToModify.size()]; + var modified = new ArrayList(itemsToModify.size()); - for (int i = 0; i < itemsToModify.size(); i++) { - UInteger itemId = itemsToModify.get(i); - BaseMonitoredItem item = subscription.getMonitoredItems().get(itemId); + for (int i = 0; i < itemsToModify.size(); i++) { + UInteger itemId = itemsToModify.get(i); + BaseMonitoredItem item = subscription.getMonitoredItems().get(itemId); - if (item != null) { - item.setMonitoringMode(monitoringMode); + if (item != null) { + item.setMonitoringMode(monitoringMode); - modified.add(item); + modified.add(item); - results[i] = StatusCode.GOOD; - } else { - results[i] = new StatusCode(StatusCodes.Bad_MonitoredItemIdInvalid); - } + results[i] = StatusCode.GOOD; + } else { + results[i] = new StatusCode(StatusCodes.Bad_MonitoredItemIdInvalid); } + } - /* - * Notify AddressSpace of the items whose MonitoringMode has been modified. - */ + /* + * Notify AddressSpace of the items whose MonitoringMode has been modified. + */ - server.getAddressSpaceManager().onMonitoringModeChanged(modified); + server.getAddressSpaceManager().onMonitoringModeChanged(modified); - /* - * Build and return results. - */ + /* + * Build and return results. + */ - ResponseHeader header = service.createResponseHeader(); - SetMonitoringModeResponse response = new SetMonitoringModeResponse( - header, - results, - new DiagnosticInfo[0] - ); + ResponseHeader header = createResponseHeader(request); - service.setResponse(response); - } catch (UaException e) { - service.setServiceFault(e); - } - } + var response = new SetMonitoringModeResponse( + header, + results, + new DiagnosticInfo[0] + ); - public void publish(ServiceRequest service) { - PublishRequest request = (PublishRequest) service.getRequest(); + return CompletableFuture.completedFuture(response); + } + public CompletableFuture publish(ServiceRequestContext context, PublishRequest request) { SubscriptionAcknowledgement[] acknowledgements = request.getSubscriptionAcknowledgements(); + StatusCode[] results; + if (acknowledgements != null) { - StatusCode[] results = new StatusCode[acknowledgements.length]; + results = new StatusCode[acknowledgements.length]; for (int i = 0; i < acknowledgements.length; i++) { SubscriptionAcknowledgement acknowledgement = acknowledgements[i]; @@ -1120,78 +1113,75 @@ public void publish(ServiceRequest service) { results[i] = subscription.acknowledge(sequenceNumber); } } - - service.attr(KEY_ACK_RESULTS).set(results); + } else { + results = new StatusCode[0]; } + PendingPublish pending = new PendingPublish(context, request, results); + if (!transferred.isEmpty()) { Subscription subscription = transferred.remove(0); - subscription.returnStatusChangeNotification( - service, + + subscription.publishStatusChangeNotification( + pending, new StatusCode(StatusCodes.Good_SubscriptionTransferred) ); - return; - } + } else if (subscriptions.isEmpty() && publishQueue.isWaitListEmpty()) { + // waitList must also be empty because the last remaining subscription could have + // expired, which removes it from bookkeeping, but leaves it in the PublishQueue + // waitList if there were no available requests to send Bad_Timeout. - // waitList must also be empty because the last remaining subscription could have - // expired, which removes it from bookkeeping, but leaves it in the PublishQueue - // waitList if there were no available requests to send Bad_Timeout. - if (subscriptions.isEmpty() && publishQueue.isWaitListEmpty()) { - service.setServiceFault(StatusCodes.Bad_NoSubscription); - return; + pending.responseFuture.completeExceptionally(new UaException(StatusCodes.Bad_NoSubscription)); + } else { + publishQueue.addRequest(pending); } - publishQueue.addRequest(service); + return pending.responseFuture; } - public void republish(ServiceRequest service) { - RepublishRequest request = (RepublishRequest) service.getRequest(); - + public CompletableFuture republish(RepublishRequest request) { if (subscriptions.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_SubscriptionIdInvalid); - return; + return failedUaFuture(StatusCodes.Bad_SubscriptionIdInvalid); } UInteger subscriptionId = request.getSubscriptionId(); Subscription subscription = subscriptions.get(subscriptionId); if (subscription == null) { - service.setServiceFault(StatusCodes.Bad_SubscriptionIdInvalid); - return; + return failedUaFuture(StatusCodes.Bad_SubscriptionIdInvalid); } UInteger sequenceNumber = request.getRetransmitSequenceNumber(); NotificationMessage notificationMessage = subscription.republish(sequenceNumber); if (notificationMessage == null) { - service.setServiceFault(StatusCodes.Bad_MessageNotAvailable); - return; + return failedUaFuture(StatusCodes.Bad_MessageNotAvailable); } - ResponseHeader header = service.createResponseHeader(); - RepublishResponse response = new RepublishResponse(header, notificationMessage); + ResponseHeader header = createResponseHeader(request); + var response = new RepublishResponse(header, notificationMessage); - service.setResponse(response); + return CompletableFuture.completedFuture(response); } - public void setTriggering(ServiceRequest service) { - SetTriggeringRequest request = (SetTriggeringRequest) service.getRequest(); + public CompletableFuture setTriggering( + ServiceRequestContext context, + SetTriggeringRequest request + ) { UInteger subscriptionId = request.getSubscriptionId(); Subscription subscription = subscriptions.get(subscriptionId); if (subscription == null) { - service.setServiceFault(StatusCodes.Bad_SubscriptionIdInvalid); - return; + return failedUaFuture(StatusCodes.Bad_SubscriptionIdInvalid); } UInteger triggerId = request.getTriggeringItemId(); - List linksToAdd = l(request.getLinksToAdd()); - List linksToRemove = l(request.getLinksToRemove()); + List linksToAdd = List.of(request.getLinksToAdd()); + List linksToRemove = List.of(request.getLinksToRemove()); if (linksToAdd.isEmpty() && linksToRemove.isEmpty()) { - service.setServiceFault(StatusCodes.Bad_NothingToDo); - return; + return failedUaFuture(StatusCodes.Bad_NothingToDo); } StatusCode[] addResults; @@ -1202,8 +1192,7 @@ public void setTriggering(ServiceRequest service) { BaseMonitoredItem triggerItem = itemsById.get(triggerId); if (triggerItem == null) { - service.setServiceFault(StatusCodes.Bad_MonitoredItemIdInvalid); - return; + return failedUaFuture(StatusCodes.Bad_MonitoredItemIdInvalid); } removeResults = linksToRemove.stream() @@ -1234,15 +1223,15 @@ public void setTriggering(ServiceRequest service) { .toArray(StatusCode[]::new); } - SetTriggeringResponse response = new SetTriggeringResponse( - service.createResponseHeader(), + var response = new SetTriggeringResponse( + createResponseHeader(request), addResults, new DiagnosticInfo[0], removeResults, new DiagnosticInfo[0] ); - service.setResponse(response); + return CompletableFuture.completedFuture(response); } public void sessionClosed(boolean deleteSubscriptions) { @@ -1277,9 +1266,9 @@ public void sessionClosed(boolean deleteSubscriptions) { if (deleteSubscriptions) { while (publishQueue.isNotEmpty()) { - ServiceRequest publishService = publishQueue.poll(); - if (publishService != null) { - publishService.setServiceFault(StatusCodes.Bad_SessionClosed); + PendingPublish pending = publishQueue.poll(); + if (pending != null) { + pending.responseFuture.completeExceptionally(new UaException(StatusCodes.Bad_SessionClosed)); } } } @@ -1340,10 +1329,10 @@ public Subscription removeSubscription(UInteger subscriptionId) { } public void sendStatusChangeNotification(Subscription subscription, StatusCode status) { - ServiceRequest service = publishQueue.poll(); + PendingPublish pending = publishQueue.poll(); - if (service != null) { - subscription.returnStatusChangeNotification(service, status); + if (pending != null) { + subscription.publishStatusChangeNotification(pending, status); } else { transferred.add(subscription); } diff --git a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/server/EndpointConfigurationTest.java b/opc-ua-sdk/sdk-server/src/test/java/org/eclipse/milo/opcua/sdk/server/api/config/EndpointConfigTest.java similarity index 78% rename from opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/server/EndpointConfigurationTest.java rename to opc-ua-sdk/sdk-server/src/test/java/org/eclipse/milo/opcua/sdk/server/api/config/EndpointConfigTest.java index 67696e4fb..b5f437928 100644 --- a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/server/EndpointConfigurationTest.java +++ b/opc-ua-sdk/sdk-server/src/test/java/org/eclipse/milo/opcua/sdk/server/api/config/EndpointConfigTest.java @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.server; +package org.eclipse.milo.opcua.sdk.server.api.config; import java.util.List; @@ -21,7 +21,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.expectThrows; -public class EndpointConfigurationTest { +public class EndpointConfigTest { @Test public void securityMismatchThrows() { @@ -29,7 +29,7 @@ public void securityMismatchThrows() { IllegalArgumentException.class, () -> // mismatch between securityPolicy and securityMode - EndpointConfiguration.newBuilder() + EndpointConfig.newBuilder() .setSecurityPolicy(SecurityPolicy.Basic128Rsa15) .setSecurityMode(MessageSecurityMode.None) .build() @@ -39,7 +39,7 @@ public void securityMismatchThrows() { IllegalArgumentException.class, () -> // mismatch between securityPolicy and securityMode - EndpointConfiguration.newBuilder() + EndpointConfig.newBuilder() .setSecurityPolicy(SecurityPolicy.None) .setSecurityMode(MessageSecurityMode.SignAndEncrypt) .build() @@ -52,7 +52,7 @@ public void missingCertificateThrows() { IllegalStateException.class, () -> // missing certificate - EndpointConfiguration.newBuilder() + EndpointConfig.newBuilder() .setSecurityPolicy(SecurityPolicy.Basic128Rsa15) .setSecurityMode(MessageSecurityMode.SignAndEncrypt) .build() @@ -64,7 +64,7 @@ public void unsupportedTransportThrows() { expectThrows( IllegalArgumentException.class, () -> - EndpointConfiguration.newBuilder() + EndpointConfig.newBuilder() .setTransportProfile(TransportProfile.HTTPS_UAXML) .build() ); @@ -72,7 +72,7 @@ public void unsupportedTransportThrows() { expectThrows( IllegalArgumentException.class, () -> - EndpointConfiguration.newBuilder() + EndpointConfig.newBuilder() .setTransportProfile(TransportProfile.HTTPS_UAJSON) .build() ); @@ -80,7 +80,7 @@ public void unsupportedTransportThrows() { expectThrows( IllegalArgumentException.class, () -> - EndpointConfiguration.newBuilder() + EndpointConfig.newBuilder() .setTransportProfile(TransportProfile.WSS_UAJSON) .build() ); @@ -88,7 +88,7 @@ public void unsupportedTransportThrows() { expectThrows( IllegalArgumentException.class, () -> - EndpointConfiguration.newBuilder() + EndpointConfig.newBuilder() .setTransportProfile(TransportProfile.WSS_UASC_UABINARY) .build() ); @@ -96,12 +96,12 @@ public void unsupportedTransportThrows() { @Test public void missingTokenPolicyDefaultsToAnonymous() { - EndpointConfiguration endpointConfiguration = - EndpointConfiguration.newBuilder().build(); + EndpointConfig endpointConfig = + EndpointConfig.newBuilder().build(); - List tokenPolicies = endpointConfiguration.getTokenPolicies(); + List tokenPolicies = endpointConfig.getTokenPolicies(); assertEquals(tokenPolicies.size(), 1); - assertEquals(tokenPolicies.get(0), EndpointConfiguration.Builder.USER_TOKEN_POLICY_ANONYMOUS); + assertEquals(tokenPolicies.get(0), EndpointConfig.Builder.USER_TOKEN_POLICY_ANONYMOUS); } } diff --git a/opc-ua-sdk/sdk-server/src/test/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfigTest.java b/opc-ua-sdk/sdk-server/src/test/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfigTest.java index 40ba8919c..832712153 100644 --- a/opc-ua-sdk/sdk-server/src/test/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfigTest.java +++ b/opc-ua-sdk/sdk-server/src/test/java/org/eclipse/milo/opcua/sdk/server/api/config/OpcUaServerConfigTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -17,10 +17,10 @@ import org.eclipse.milo.opcua.sdk.server.identity.AnonymousIdentityValidator; import org.eclipse.milo.opcua.stack.core.security.DefaultCertificateManager; +import org.eclipse.milo.opcua.stack.core.security.DefaultServerCertificateValidator; import org.eclipse.milo.opcua.stack.core.security.DefaultTrustListManager; import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; import org.eclipse.milo.opcua.stack.core.types.structured.BuildInfo; -import org.eclipse.milo.opcua.stack.server.security.DefaultServerCertificateValidator; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; @@ -42,7 +42,7 @@ public void testCopy() throws IOException { .setIdentityValidator(AnonymousIdentityValidator.INSTANCE) .setBuildInfo(new BuildInfo("a", "b", "c", "d", "e", DateTime.MIN_VALUE)) .setLimits(new OpcUaServerConfigLimits() {}) - .setScheduledExecutorService(scheduledExecutorService) + .setScheduledExecutor(scheduledExecutorService) .build(); OpcUaServerConfig copy = OpcUaServerConfig.copy(original).build(); diff --git a/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/TestClientCertificateValidator.java b/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/TestClientCertificateValidator.java index f5c2e52f2..f9f1ba57b 100644 --- a/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/TestClientCertificateValidator.java +++ b/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/TestClientCertificateValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -16,7 +16,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.ClientCertificateValidator; public class TestClientCertificateValidator implements ClientCertificateValidator { diff --git a/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/config/OpcUaClientConfigTest.java b/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/config/OpcUaClientConfigTest.java index 36fdb67a1..38bb283ff 100644 --- a/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/config/OpcUaClientConfigTest.java +++ b/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/config/OpcUaClientConfigTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -46,7 +46,6 @@ public void testCopy() { .setEndpoint(endpoint) .setSessionName(() -> "testSessionName") .setSessionTimeout(uint(60000 * 60)) - .setRequestTimeout(uint(120000)) .setMaxResponseMessageSize(UInteger.MAX) .setMaxPendingPublishRequests(uint(2)) .setIdentityProvider(new AnonymousProvider()) @@ -58,7 +57,6 @@ public void testCopy() { assertEquals(copy.getSessionName(), original.getSessionName()); assertEquals(copy.getSessionTimeout(), original.getSessionTimeout()); - assertEquals(copy.getRequestTimeout(), original.getRequestTimeout()); assertEquals(copy.getMaxResponseMessageSize(), original.getMaxResponseMessageSize()); assertEquals(copy.getMaxPendingPublishRequests(), original.getMaxPendingPublishRequests()); assertEquals(copy.getIdentityProvider(), original.getIdentityProvider()); @@ -75,7 +73,6 @@ public void testCopyAndModify() { .setEndpoint(endpoint) .setSessionName(() -> "testSessionName") .setSessionTimeout(uint(60000 * 60)) - .setRequestTimeout(uint(120000)) .setMaxResponseMessageSize(UInteger.MAX) .setMaxPendingPublishRequests(uint(2)) .setIdentityProvider(new AnonymousProvider()) @@ -86,7 +83,6 @@ public void testCopyAndModify() { builder -> builder.setSessionName(() -> "foo") .setSessionTimeout(uint(0)) - .setRequestTimeout(uint(0)) .setMaxResponseMessageSize(uint(0)) .setMaxPendingPublishRequests(uint(0)) .setIdentityProvider(new AnonymousProvider()) @@ -101,7 +97,6 @@ public void testCopyAndModify() { assertNotEquals(copy.getSessionLocaleIds(), original.getSessionLocaleIds()); assertEquals(copy.getSessionTimeout(), uint(0)); - assertEquals(copy.getRequestTimeout(), uint(0)); assertEquals(copy.getMaxResponseMessageSize(), uint(0)); assertEquals(copy.getMaxPendingPublishRequests(), uint(0)); assertEquals(copy.getKeepAliveFailuresAllowed(), uint(2)); diff --git a/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsmTest.java b/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsmTest.java index 54b3052b1..8c342886f 100644 --- a/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsmTest.java +++ b/opc-ua-sdk/sdk-tests/src/test/java/org/eclipse/milo/opcua/sdk/client/session/SessionFsmTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -19,7 +19,6 @@ import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; import org.testng.annotations.Test; -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; import static org.testng.Assert.assertNotNull; public class SessionFsmTest { @@ -39,7 +38,6 @@ public void testCloseSessionWhileInactive() throws Exception { )) .setApplicationName(LocalizedText.english("Eclipse Milo Test Client")) .setApplicationUri("urn:eclipse:milo:examples:client") - .setRequestTimeout(uint(60000)) .build(); OpcUaClient client = OpcUaClient.create(clientConfig); diff --git a/opc-ua-stack/pom.xml b/opc-ua-stack/pom.xml index e32444e44..e80bbe87f 100644 --- a/opc-ua-stack/pom.xml +++ b/opc-ua-stack/pom.xml @@ -26,10 +26,11 @@ encoding-json encoding-xml guava-dependencies - stack-client stack-core - stack-server stack-tests + transport + transport-https + transport-websocket diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/UaStackClient.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/UaStackClient.java deleted file mode 100644 index aed22e3e6..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/UaStackClient.java +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client; - -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; - -import org.eclipse.milo.opcua.stack.client.transport.UaTransport; -import org.eclipse.milo.opcua.stack.client.transport.http.OpcHttpTransport; -import org.eclipse.milo.opcua.stack.client.transport.tcp.OpcTcpTransport; -import org.eclipse.milo.opcua.stack.client.transport.websocket.OpcWebSocketTransport; -import org.eclipse.milo.opcua.stack.core.NamespaceTable; -import org.eclipse.milo.opcua.stack.core.ServerTable; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.UaServiceFaultException; -import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; -import org.eclipse.milo.opcua.stack.core.encoding.DefaultEncodingManager; -import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; -import org.eclipse.milo.opcua.stack.core.encoding.EncodingManager; -import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; -import org.eclipse.milo.opcua.stack.core.types.DataTypeManager; -import org.eclipse.milo.opcua.stack.core.types.DefaultDataTypeManager; -import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; -import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; -import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; -import org.eclipse.milo.opcua.stack.core.util.ExecutionQueue; -import org.eclipse.milo.opcua.stack.core.util.LongSequence; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - -public class UaStackClient { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final LongSequence requestHandles = new LongSequence(0, UInteger.MAX_VALUE); - - private final Map> pending = new ConcurrentHashMap<>(); - - private final NamespaceTable namespaceTable = new NamespaceTable(); - private final ServerTable serverTable = new ServerTable(); - - private final DataTypeManager staticDataTypeManager = - DefaultDataTypeManager.createAndInitialize(namespaceTable); - - private final DataTypeManager dynamicDataTypeManager = - DefaultDataTypeManager.createAndInitialize(namespaceTable); - - private final EncodingManager encodingManager = - DefaultEncodingManager.createAndInitialize(); - - private final EncodingContext staticEncodingContext; - private final EncodingContext dynamicEncodingContext; - - private final UaTransport transport; - private final ExecutionQueue deliveryQueue; - - private final UaStackClientConfig config; - - public UaStackClient( - UaStackClientConfig config, - Function transportFactory - ) { - - this.config = config; - - if (config.getEndpoint() != null && config.getEndpoint().getServer() != null) { - // might be null if e.g. this is being used by DiscoveryClient - serverTable.add(config.getEndpoint().getServer().getApplicationUri()); - } - - deliveryQueue = new ExecutionQueue(config.getExecutor()); - - staticEncodingContext = new EncodingContext() { - @Override - public DataTypeManager getDataTypeManager() { - return staticDataTypeManager; - } - - @Override - public EncodingManager getEncodingManager() { - return null; - } - - @Override - public EncodingLimits getEncodingLimits() { - return config.getEncodingLimits(); - } - - @Override - public NamespaceTable getNamespaceTable() { - return namespaceTable; - } - - @Override - public ServerTable getServerTable() { - return serverTable; - } - }; - - dynamicEncodingContext = new EncodingContext() { - @Override - public DataTypeManager getDataTypeManager() { - return dynamicDataTypeManager; - } - - @Override - public EncodingManager getEncodingManager() { - return encodingManager; - } - - @Override - public EncodingLimits getEncodingLimits() { - return config.getEncodingLimits(); - } - - @Override - public NamespaceTable getNamespaceTable() { - return namespaceTable; - } - - @Override - public ServerTable getServerTable() { - return serverTable; - } - }; - - transport = transportFactory.apply(this); - } - - /** - * @return the {@link UaStackClientConfig} this client was created with. - */ - public UaStackClientConfig getConfig() { - return config; - } - - /** - * Connect this {@link UaStackClient} to the server in the configured endpoint. - *

- * Depending on the underlying transport this may or may not actually make a connection attempt. - * - * @return this {@link UaStackClient}. - */ - public CompletableFuture connect() { - return transport.connect() - .thenApply(t -> UaStackClient.this); - } - - /** - * Disconnect this {@link UaStackClient} from the server in the configured endpoint. - *

- * Depending on the underlying transport this may or may not actually make a disconnect attempt. - * - * @return this {@link UaStackClient}. - */ - public CompletableFuture disconnect() { - return transport.disconnect() - .whenComplete((u, ex) -> { - UaException disconnect = new UaException( - StatusCodes.Bad_Disconnect, "client disconnect"); - - pending.forEach((h, cf) -> cf.completeExceptionally(disconnect)); - pending.clear(); - }) - .thenApply(t -> UaStackClient.this); - } - - /** - * Get the {@link UaTransport} used by this client. - * - * @return the {@link UaTransport} used by this client. - */ - public UaTransport getTransport() { - return transport; - } - - /** - * Get the local copy of the {@link NamespaceTable}. - *

- * Until explicitly updated this contains only - * {@link org.eclipse.milo.opcua.stack.core.util.Namespaces#OPC_UA} at index 0. - * - * @return the local copy of the {@link NamespaceTable}. - */ - public NamespaceTable getNamespaceTable() { - return namespaceTable; - } - - /** - * Get the local copy of the {@link ServerTable}. - *

- * Until explicitly updated this contains only the server application URI from the - * {@link org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription} in the - * configured endpoint, if present. - * - * @return the local copy of the {@link ServerTable}. - */ - public ServerTable getServerTable() { - return serverTable; - } - - /** - * Get the client's "static" {@link DataTypeManager}. - *

- * This {@link DataTypeManager} is for static codecs that serialize classes that exist at - * compile time, e.g. structures from namespace 0 and or code-generated structures. - * - * @return the client's static {@link DataTypeManager}. - */ - public DataTypeManager getStaticDataTypeManager() { - return staticDataTypeManager; - } - - /** - * Get the client's "dynamic" {@link DataTypeManager}. - *

- * This {@link DataTypeManager} is for dynamic codecs that were created by reading the server's - * DataType Dictionary at runtime and serializes generic representations of structures used by - * instances of a BsdParser implementation. - * - * @return the client's dynamic {@link DataTypeManager}. - */ - public DataTypeManager getDynamicDataTypeManager() { - return dynamicDataTypeManager; - } - - /** - * Get a "static" {@link EncodingContext} instance. - *

- * This {@link EncodingContext} instance returns the client's static {@link DataTypeManager}. - * - * @return a "static" {@link EncodingContext} instance. - * @see #getStaticDataTypeManager() - */ - public EncodingContext getStaticEncodingContext() { - return staticEncodingContext; - } - - /** - * Get a "dynamic" {@link EncodingContext}. - *

- * This {@link EncodingContext} instance returns the client's dynamic {@link DataTypeManager}. - * - * @return a "dynamic" {@link EncodingContext}. - * @see #getDynamicDataTypeManager() - */ - public EncodingContext getDynamicEncodingContext() { - return dynamicEncodingContext; - } - - /** - * Create a new {@link RequestHeader} with a null authentication token. - *

- * A unique request handle will be automatically assigned to the header. - * - * @return a new {@link RequestHeader} with a null authentication token. - */ - public RequestHeader newRequestHeader() { - return newRequestHeader(NodeId.NULL_VALUE); - } - - /** - * Create a new {@link RequestHeader} with {@code authToken}. - *

- * A unique request handle will be automatically assigned to the header. - * - * @param authToken the authentication token to create the header with. - * @return a new {@link RequestHeader} created with {@code authToken}. - */ - public RequestHeader newRequestHeader(NodeId authToken) { - return newRequestHeader(authToken, config.getRequestTimeout()); - } - - /** - * Create a new {@link RequestHeader} with {@code authToken} and {@code requestTimeout}. - *

- * A unique request handle will be automatically assigned to the header. - * - * @param authToken the authentication token to create the header with. - * @param requestTimeout the timeout hint to create the header with.f - * @return a new {@link RequestHeader} created with {@code authToken} and {@code requestTimeout}. - */ - public RequestHeader newRequestHeader(NodeId authToken, UInteger requestTimeout) { - return new RequestHeader( - authToken, - DateTime.now(), - uint(requestHandles.getAndIncrement()), - uint(0), - null, - requestTimeout, - null - ); - } - - /** - * Send a {@link UaRequestMessageType} to the connected server. - *

- * The {@link RequestHeader} of {@code request} must have a unique request handle. Use the - * {@code newRequestHeader} helper functions to create headers for {@link UaRequestMessageType}s. - * - * @param request the {@link UaRequestMessageType} to send. - * @return a {@link CompletableFuture} containing the eventual {@link UaResponseMessageType} from the server. - * @see #newRequestHeader() - * @see #newRequestHeader(NodeId) - * @see #newRequestHeader(NodeId, UInteger) - */ - public CompletableFuture sendRequest(UaRequestMessageType request) { - RequestHeader requestHeader = request.getRequestHeader(); - UInteger requestHandle = requestHeader.getRequestHandle(); - - final CompletableFuture future = new CompletableFuture<>(); - pending.put(requestHandle, future); - - transport.sendRequest(request).whenComplete((response, ex) -> { - pending.remove(requestHandle); - - deliverResponse(request, response, ex, future); - }); - - return future; - } - - /** - * Complete {@code future} with {@code response} on the {@code deliveryQueue}. - *

- * This is done for two reasons: - * 1. the transport future is completed on its serialization queue thread, which we want to get off of ASAP. - * 2. the futures need to be completed serially, in the order received from the server. - * - * @param request the original {@link UaRequestMessageType}. - * @param response the {@link UaResponseMessageType}. - * @param future the {@link CompletableFuture} awaiting completion. - */ - private void deliverResponse( - UaRequestMessageType request, - @Nullable UaResponseMessageType response, - @Nullable Throwable failure, - CompletableFuture future - ) { - - deliveryQueue.submit(() -> { - if (response != null) { - ResponseHeader header = response.getResponseHeader(); - UInteger requestHandle = header.getRequestHandle(); - - if (header.getServiceResult().isGood()) { - future.complete(response); - } else { - ServiceFault serviceFault; - - if (response instanceof ServiceFault) { - serviceFault = (ServiceFault) response; - } else { - serviceFault = new ServiceFault(header); - } - - if (logger.isDebugEnabled()) { - logger.debug( - "Received ServiceFault request={} requestHandle={}, result={}", - request.getClass().getSimpleName(), - requestHandle, - header.getServiceResult() - ); - } - - future.completeExceptionally(new UaServiceFaultException(serviceFault)); - } - } else { - assert failure != null; - - if (logger.isDebugEnabled()) { - logger.debug( - "sendRequest() failed, request={}, requestHandle={}", - request.getClass().getSimpleName(), - request.getRequestHeader().getRequestHandle(), - failure - ); - } - - future.completeExceptionally(failure); - } - }); - } - - /** - * Create a {@link UaStackClient} with {@code config}. - *

- * The {@link UaTransport} instance to create will be inferred from the transport profile URI in the configured - * endpoint. - *

- * Supported transports: - *

    - *
  • TCP + UA Binary
  • - *
  • HTTP(s) + UA Binary
  • - *
- *

- * Experimentally supported: - *

    - *
  • WebSocket + UA Binary
  • - *
- *

- * Not supported: - *

    - *
  • HTTP(s) + UA JSON
  • - *
  • HTTP(s) + UA XML
  • - *
  • WebSocket + UA JSON
  • - *
- * - * @param config the {@link UaStackClientConfig}. - * @return a {@link UaStackClient} created with {@code config}. - * @throws UaException if the transport is unsupported. - */ - public static UaStackClient create(UaStackClientConfig config) throws UaException { - String transportProfileUri = - config.getEndpoint().getTransportProfileUri(); - - TransportProfile transportProfile = - TransportProfile.fromUri(transportProfileUri); - - Function transportFactory; - - switch (transportProfile) { - case TCP_UASC_UABINARY: - transportFactory = OpcTcpTransport::new; - break; - - case HTTPS_UABINARY: - transportFactory = OpcHttpTransport::new; - break; - - case WSS_UASC_UABINARY: - transportFactory = OpcWebSocketTransport::new; - break; - - case HTTPS_UAXML: - case HTTPS_UAJSON: - case WSS_UAJSON: - default: - throw new UaException( - StatusCodes.Bad_InternalError, - "unsupported transport: " + transportProfileUri); - } - - return new UaStackClient(config, transportFactory); - } - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/UaStackClientConfig.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/UaStackClientConfig.java deleted file mode 100644 index bb11fd89f..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/UaStackClientConfig.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client; - -import java.security.KeyPair; -import java.security.cert.X509Certificate; -import java.util.Optional; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ScheduledExecutorService; -import java.util.function.Consumer; - -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.util.HashedWheelTimer; -import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator; -import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; - -public interface UaStackClientConfig { - - /** - * Get the endpoint to connect to. - * - * @return the {@link EndpointDescription} to connect to. - */ - EndpointDescription getEndpoint(); - - /** - * Get the {@link KeyPair} to use. - *

- * May be absent if connecting without security, must be present if connecting with security. - * - * @return an {@link Optional} containing the {@link KeyPair} to use. - */ - Optional getKeyPair(); - - /** - * Get the {@link X509Certificate} to use. - *

- * May be absent if connecting without security, must be present if connecting with security. - * - * @return an {@link Optional} containing the {@link X509Certificate} to use. - */ - Optional getCertificate(); - - /** - * Get the {@link X509Certificate} to use as well as any certificates in the certificate chain. - * - * @return the {@link X509Certificate} to use as well as any certificates in the certificate chain. - */ - Optional getCertificateChain(); - - /** - * Get the {@link ClientCertificateValidator} this client will use to validate server certificates when connecting. - * - * @return the validator this client will use to validate server certificates when connecting. - */ - ClientCertificateValidator getCertificateValidator(); - - /** - * @return the configured {@link EncodingLimits}. - */ - EncodingLimits getEncodingLimits(); - - /** - * @return the {@link ExecutorService} used by the client. - */ - ExecutorService getExecutor(); - - /** - * @return the {@link ScheduledExecutorService} used by the client. - */ - ScheduledExecutorService getScheduledExecutor(); - - /** - * @return the {@link NioEventLoopGroup} used by the client. - */ - NioEventLoopGroup getEventLoop(); - - /** - * @return the {@link HashedWheelTimer} used by the client. - */ - HashedWheelTimer getWheelTimer(); - - /** - * @return the timeout, in milliseconds, when opening a socket connection to a remote host. - */ - UInteger getConnectTimeout(); - - /** - * @return the timeout, in milliseconds, to wait for an Acknowledge message in response to the client's - * Hello message. - */ - UInteger getAcknowledgeTimeout(); - - /** - * @return the timeout, in milliseconds, before failing a request due to timeout. - */ - UInteger getRequestTimeout(); - - /** - * @return the secure channel lifetime to request, in milliseconds. - */ - UInteger getChannelLifetime(); - - static UaStackClientConfigBuilder builder() { - return new UaStackClientConfigBuilder(); - } - - /** - * Copy the values from an existing {@link UaStackClientConfig} into a new {@link UaStackClientConfigBuilder}. - * This builder can be used to make any desired modifications before invoking - * {@link UaStackClientConfigBuilder#build()} to produce a new config. - * - * @param config the {@link UaStackClientConfig} to copy from. - * @return a {@link UaStackClientConfigBuilder} pre-populated with values from {@code config}. - */ - static UaStackClientConfigBuilder copy(UaStackClientConfig config) { - UaStackClientConfigBuilder builder = new UaStackClientConfigBuilder(); - - builder.setEndpoint(config.getEndpoint()); - config.getKeyPair().ifPresent(builder::setKeyPair); - config.getCertificate().ifPresent(builder::setCertificate); - config.getCertificateChain().ifPresent(builder::setCertificateChain); - builder.setCertificateValidator(config.getCertificateValidator()); - builder.setEncodingLimits(config.getEncodingLimits()); - builder.setChannelLifetime(config.getChannelLifetime()); - builder.setExecutor(config.getExecutor()); - builder.setScheduledExecutor(config.getScheduledExecutor()); - builder.setEventLoop(config.getEventLoop()); - builder.setWheelTimer(config.getWheelTimer()); - builder.setConnectTimeout(config.getConnectTimeout()); - builder.setAcknowledgeTimeout(config.getAcknowledgeTimeout()); - builder.setRequestTimeout(config.getRequestTimeout()); - - return builder; - } - - /** - * Copy the values from an existing {@link UaStackClientConfig} into a new {@link UaStackClientConfigBuilder} - * and then submit the builder to the provided consumer for modification. - * - * @param config the {@link UaStackClientConfig} to copy from. - * @param consumer a {@link Consumer} that may modify the builder. - * @return a {@link UaStackClientConfig} built from the builder provided to {@code consumer}. - */ - static UaStackClientConfig copy( - UaStackClientConfig config, - Consumer consumer) { - - UaStackClientConfigBuilder builder = copy(config); - - consumer.accept(builder); - - return builder.build(); - } - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/UaStackClientConfigBuilder.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/UaStackClientConfigBuilder.java deleted file mode 100644 index 373ff343b..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/UaStackClientConfigBuilder.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client; - -import java.security.KeyPair; -import java.security.cert.X509Certificate; -import java.util.Optional; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ScheduledExecutorService; - -import com.google.common.base.Preconditions; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.util.HashedWheelTimer; -import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator; -import org.eclipse.milo.opcua.stack.core.Stack; -import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.jetbrains.annotations.Nullable; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - -public class UaStackClientConfigBuilder { - - private EndpointDescription endpoint; - private KeyPair keyPair; - private X509Certificate certificate; - private X509Certificate[] certificateChain; - private ClientCertificateValidator certificateValidator = new ClientCertificateValidator.InsecureValidator(); - - private ExecutorService executor; - private ScheduledExecutorService scheduledExecutor; - private NioEventLoopGroup eventLoop; - private HashedWheelTimer wheelTimer; - - private EncodingLimits encodingLimits = EncodingLimits.DEFAULT; - private UInteger connectTimeout = uint(5_000); - private UInteger acknowledgeTimeout = uint(5_000); - private UInteger requestTimeout = uint(60_000); - private UInteger channelLifetime = uint(60 * 60 * 1000); - - public UaStackClientConfigBuilder setEndpoint(EndpointDescription endpoint) { - this.endpoint = endpoint; - return this; - } - - public UaStackClientConfigBuilder setKeyPair(KeyPair keyPair) { - this.keyPair = keyPair; - return this; - } - - public UaStackClientConfigBuilder setCertificate(X509Certificate certificate) { - this.certificate = certificate; - return this; - } - - public UaStackClientConfigBuilder setCertificateChain(X509Certificate[] certificateChain) { - this.certificateChain = certificateChain; - return this; - } - - public UaStackClientConfigBuilder setCertificateValidator(ClientCertificateValidator certificateValidator) { - this.certificateValidator = certificateValidator; - return this; - } - - public UaStackClientConfigBuilder setExecutor(ExecutorService executor) { - this.executor = executor; - return this; - } - - public UaStackClientConfigBuilder setScheduledExecutor(ScheduledExecutorService scheduledExecutor) { - this.scheduledExecutor = scheduledExecutor; - return this; - } - - public UaStackClientConfigBuilder setEventLoop(NioEventLoopGroup eventLoop) { - this.eventLoop = eventLoop; - return this; - } - - public UaStackClientConfigBuilder setWheelTimer(HashedWheelTimer wheelTimer) { - this.wheelTimer = wheelTimer; - return this; - } - - public UaStackClientConfigBuilder setEncodingLimits(EncodingLimits encodingLimits) { - this.encodingLimits = encodingLimits; - return this; - } - - public UaStackClientConfigBuilder setConnectTimeout(UInteger connectTimeout) { - this.connectTimeout = connectTimeout; - return this; - } - - public UaStackClientConfigBuilder setAcknowledgeTimeout(UInteger acknowledgeTimeout) { - this.acknowledgeTimeout = acknowledgeTimeout; - return this; - } - - public UaStackClientConfigBuilder setRequestTimeout(UInteger requestTimeout) { - this.requestTimeout = requestTimeout; - return this; - } - - public UaStackClientConfigBuilder setChannelLifetime(UInteger channelLifetime) { - this.channelLifetime = channelLifetime; - return this; - } - - public UaStackClientConfig build() { - Preconditions.checkNotNull(endpoint, "endpoint must be non-null"); - - if (executor == null) { - executor = Stack.sharedExecutor(); - } - if (scheduledExecutor == null) { - scheduledExecutor = Stack.sharedScheduledExecutor(); - } - if (eventLoop == null) { - eventLoop = Stack.sharedEventLoop(); - } - if (wheelTimer == null) { - wheelTimer = Stack.sharedWheelTimer(); - } - - return new UaStackClientConfigImpl( - endpoint, - keyPair, - certificate, - certificateChain, - certificateValidator, - encodingLimits, - executor, - scheduledExecutor, - eventLoop, - wheelTimer, - connectTimeout, - acknowledgeTimeout, - requestTimeout, - channelLifetime - ); - } - - static class UaStackClientConfigImpl implements UaStackClientConfig { - - private final EndpointDescription endpoint; - private final KeyPair keyPair; - private final X509Certificate certificate; - private final X509Certificate[] certificateChain; - private final ClientCertificateValidator certificateValidator; - - private final EncodingLimits encodingLimits; - private final ExecutorService executor; - private final ScheduledExecutorService scheduledExecutor; - private final NioEventLoopGroup eventLoop; - private final HashedWheelTimer wheelTimer; - private final UInteger connectTimeout; - private final UInteger acknowledgeTimeout; - private final UInteger requestTimeout; - private final UInteger channelLifetime; - - UaStackClientConfigImpl( - EndpointDescription endpoint, - @Nullable KeyPair keyPair, - @Nullable X509Certificate certificate, - @Nullable X509Certificate[] certificateChain, - ClientCertificateValidator certificateValidator, - EncodingLimits encodingLimits, - ExecutorService executor, - ScheduledExecutorService scheduledExecutor, - NioEventLoopGroup eventLoop, - HashedWheelTimer wheelTimer, - UInteger connectTimeout, - UInteger acknowledgeTimeout, - UInteger requestTimeout, - UInteger channelLifetime - ) { - - this.endpoint = endpoint; - this.keyPair = keyPair; - this.certificate = certificate; - this.certificateChain = certificateChain; - this.certificateValidator = certificateValidator; - this.encodingLimits = encodingLimits; - this.executor = executor; - this.scheduledExecutor = scheduledExecutor; - this.eventLoop = eventLoop; - this.wheelTimer = wheelTimer; - this.connectTimeout = connectTimeout; - this.acknowledgeTimeout = acknowledgeTimeout; - this.requestTimeout = requestTimeout; - this.channelLifetime = channelLifetime; - } - - @Override - public EndpointDescription getEndpoint() { - return endpoint; - } - - @Override - public Optional getKeyPair() { - return Optional.ofNullable(keyPair); - } - - @Override - public Optional getCertificate() { - return Optional.ofNullable(certificate); - } - - @Override - public Optional getCertificateChain() { - if (certificateChain != null) { - return Optional.of(certificateChain); - } else { - if (certificate != null) { - return Optional.of(new X509Certificate[]{certificate}); - } else { - return Optional.empty(); - } - } - } - - @Override - public ClientCertificateValidator getCertificateValidator() { - return certificateValidator; - } - - @Override - public EncodingLimits getEncodingLimits() { - return encodingLimits; - } - - @Override - public UInteger getChannelLifetime() { - return channelLifetime; - } - - @Override - public ExecutorService getExecutor() { - return executor; - } - - @Override - public ScheduledExecutorService getScheduledExecutor() { - return scheduledExecutor; - } - - @Override - public NioEventLoopGroup getEventLoop() { - return eventLoop; - } - - @Override - public HashedWheelTimer getWheelTimer() { - return wheelTimer; - } - - @Override - public UInteger getConnectTimeout() { - return connectTimeout; - } - - @Override - public UInteger getAcknowledgeTimeout() { - return acknowledgeTimeout; - } - - @Override - public UInteger getRequestTimeout() { - return requestTimeout; - } - - } - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/AbstractTransport.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/AbstractTransport.java deleted file mode 100644 index 9749913de..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/AbstractTransport.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.transport; - -import java.nio.channels.ClosedChannelException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -import io.netty.channel.Channel; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timeout; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; -import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class AbstractTransport implements UaTransport { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final HashedWheelTimer wheelTimer; - - private final UaStackClientConfig config; - - public AbstractTransport(UaStackClientConfig config) { - this.config = config; - - wheelTimer = config.getWheelTimer(); - } - - /** - * Get the {@link UaStackClientConfig} of the {@link UaStackClient} this transport instance belongs to. - * - * @return the {@link UaStackClientConfig} of the {@link UaStackClient} this transport instance belongs to. - */ - public UaStackClientConfig getConfig() { - return config; - } - - /** - * Get a {@link Channel} suitable for sending a request on. - *

- * The Channel must have a handler capable of matching inbound responses to pending outbound - * {@link UaTransportRequest}s. - * - * @return a {@link Channel} suitable for sending a request on. - */ - public abstract CompletableFuture channel(); - - @Override - public CompletableFuture sendRequest(UaRequestMessageType request) { - return channel().thenCompose(channel -> sendRequest(request, channel, true)); - } - - protected CompletableFuture sendRequest( - UaRequestMessageType request, - Channel channel, - boolean firstAttempt) { - - UaTransportRequest transportRequest = new UaTransportRequest(request); - - scheduleRequestTimeout(transportRequest); - - transportRequest.getFuture().whenComplete( - (response, ex) -> - cancelRequestTimeout(transportRequest) - ); - - channel.writeAndFlush(transportRequest).addListener(f -> { - if (!f.isSuccess()) { - Throwable cause = f.cause(); - - if (cause instanceof ClosedChannelException && firstAttempt) { - logger.debug("Write failed, channel closed; retrying..."); - - config.getScheduledExecutor().schedule( - () -> config.getExecutor().execute(() -> { - CompletableFuture sendAgain = - channel().thenCompose(ch -> sendRequest(request, ch, false)); - - sendAgain.whenComplete((r, ex) -> { - if (r != null) { - transportRequest.getFuture().complete(r); - } else { - transportRequest.getFuture().completeExceptionally(ex); - } - }); - }), - 1, - TimeUnit.SECONDS - ); - } else { - transportRequest.getFuture().completeExceptionally(cause); - - logger.debug( - "Write failed, request={}, requestHandle={}", - request.getClass().getSimpleName(), - request.getRequestHeader().getRequestHandle()); - } - } else { - if (logger.isTraceEnabled()) { - logger.trace( - "Write succeeded for request={}, requestHandle={}", - request.getClass().getSimpleName(), - request.getRequestHeader().getRequestHandle()); - } - } - }); - - return transportRequest.getFuture(); - } - - private void scheduleRequestTimeout(UaTransportRequest transportRequest) { - RequestHeader requestHeader = transportRequest.getRequest().getRequestHeader(); - - long timeoutHint = requestHeader.getTimeoutHint() != null ? - requestHeader.getTimeoutHint().longValue() : 0L; - - if (timeoutHint > 0) { - Timeout timeout = wheelTimer.newTimeout( - t -> { - UaException exception = new UaException( - StatusCodes.Bad_Timeout, - String.format( - "requestId=%s timed out after %sms", - requestHeader.getRequestHandle(), timeoutHint) - ); - - transportRequest.getFuture().completeExceptionally(exception); - }, - timeoutHint, - TimeUnit.MILLISECONDS - ); - - transportRequest.setTimeout(timeout); - } - } - - private void cancelRequestTimeout(UaTransportRequest transportRequest) { - Timeout timeout = transportRequest.getTimeout(); - if (timeout != null) timeout.cancel(); - } - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/UaTransport.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/UaTransport.java deleted file mode 100644 index 7cf1d0c38..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/UaTransport.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.transport; - -import java.util.concurrent.CompletableFuture; - -import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; - -public interface UaTransport { - - /** - * Connect this transport. - *

- * Some transports may actually be connection-less (e.g. HTTP), making this method a misnomer, but it should be - * called to initialize the transport regardless. - * - * @return the connected {@link UaTransport} instance. - */ - CompletableFuture connect(); - - /** - * Disconnect this transport. - *

- * Some transports may actually be connection-less (e.g. HTTP), making this method a misnomer, but it should be - * called to un-initialize the transport regardless. - * - * @return the disconnected {@link UaTransport} instance. - */ - CompletableFuture disconnect(); - - /** - * Send a {@link UaRequestMessageType}, returning a {@link CompletableFuture} representing the result of the operation. - * - * @param request the {@link UaRequestMessageType} to send. - * @return a {@link CompletableFuture} representing the result of the operation. - */ - CompletableFuture sendRequest(UaRequestMessageType request); - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/UaTransportRequest.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/UaTransportRequest.java deleted file mode 100644 index 56031c782..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/UaTransportRequest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.transport; - -import java.util.concurrent.CompletableFuture; - -import io.netty.util.Timeout; -import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; -import org.jetbrains.annotations.Nullable; - -public class UaTransportRequest { - - private volatile Timeout timeout; - - private final UaRequestMessageType request; - private final CompletableFuture future; - - public UaTransportRequest(UaRequestMessageType request) { - this(request, new CompletableFuture<>()); - } - - public UaTransportRequest(UaRequestMessageType request, CompletableFuture future) { - this.request = request; - this.future = future; - } - - public UaRequestMessageType getRequest() { - return request; - } - - public CompletableFuture getFuture() { - return future; - } - - public synchronized void setTimeout(Timeout timeout) { - this.timeout = timeout; - } - - @Nullable - public synchronized Timeout getTimeout() { - return timeout; - } - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/tcp/OpcClientTcpChannelInitializer.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/tcp/OpcClientTcpChannelInitializer.java deleted file mode 100644 index 4ab5bc8f1..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/tcp/OpcClientTcpChannelInitializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.transport.tcp; - -import java.util.concurrent.CompletableFuture; - -import io.netty.channel.ChannelInitializer; -import io.netty.channel.socket.SocketChannel; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel; -import org.eclipse.milo.opcua.stack.client.transport.uasc.UascClientAcknowledgeHandler; - -public class OpcClientTcpChannelInitializer extends ChannelInitializer { - - private final UaStackClient client; - private final CompletableFuture handshake; - - public OpcClientTcpChannelInitializer( - UaStackClient client, - CompletableFuture handshake) { - - this.client = client; - this.handshake = handshake; - } - - @Override - protected void initChannel(SocketChannel channel) throws Exception { - channel.pipeline().addLast(new UascClientAcknowledgeHandler(client, handshake)); - } - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/tcp/OpcTcpTransport.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/tcp/OpcTcpTransport.java deleted file mode 100644 index 4fba34d73..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/tcp/OpcTcpTransport.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.transport.tcp; - -import java.util.concurrent.CompletableFuture; - -import com.digitalpetri.netty.fsm.ChannelFsm; -import io.netty.channel.Channel; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.client.transport.AbstractTransport; -import org.eclipse.milo.opcua.stack.client.transport.UaTransport; -import org.eclipse.milo.opcua.stack.client.transport.uasc.ClientChannelFsm; - -public class OpcTcpTransport extends AbstractTransport implements UaTransport { - - private final ChannelFsm channelFsm; - - private final UaStackClient client; - - public OpcTcpTransport(UaStackClient client) { - super(client.getConfig()); - - this.client = client; - - channelFsm = ClientChannelFsm.newChannelFsm(client); - } - - @Override - public UaStackClientConfig getConfig() { - return client.getConfig(); - } - - @Override - public CompletableFuture connect() { - return channelFsm.connect() - .thenApply(v -> OpcTcpTransport.this); - } - - @Override - public CompletableFuture disconnect() { - return channelFsm.disconnect() - .thenApply(v -> OpcTcpTransport.this); - } - - @Override - public CompletableFuture channel() { - return channelFsm.getChannel(); - } - - /** - * @return the {@link ChannelFsm} used by this transport. - */ - public ChannelFsm channelFsm() { - return channelFsm; - } - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/ClientChannelFsm.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/ClientChannelFsm.java deleted file mode 100644 index 9d9c495a4..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/ClientChannelFsm.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.transport.uasc; - -import java.net.ConnectException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -import com.digitalpetri.netty.fsm.ChannelActions; -import com.digitalpetri.netty.fsm.ChannelFsm; -import com.digitalpetri.netty.fsm.ChannelFsmConfig; -import com.digitalpetri.netty.fsm.ChannelFsmFactory; -import com.digitalpetri.netty.fsm.Event; -import com.digitalpetri.netty.fsm.State; -import com.digitalpetri.strictmachine.FsmContext; -import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.ConnectTimeoutException; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.util.Timeout; -import io.netty.util.TimerTask; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.client.transport.tcp.OpcClientTcpChannelInitializer; -import org.eclipse.milo.opcua.stack.client.transport.websocket.OpcClientWebSocketChannelInitializer; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; -import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; -import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; -import org.eclipse.milo.opcua.stack.core.types.structured.CloseSecureChannelRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; -import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - -public class ClientChannelFsm { - - private static final String CHANNEL_FSM_LOGGER_NAME = "org.eclipse.milo.opcua.stack.client.ChannelFsm"; - - public static ChannelFsm newChannelFsm(UaStackClient client) { - ChannelFsmConfig fsmConfig = ChannelFsmConfig.newBuilder() - .setLazy(false) // reconnect immediately - .setMaxIdleSeconds(0) // keep alive handled by SessionFsm - .setMaxReconnectDelaySeconds(16) - .setPersistent(true) - .setChannelActions(new ClientChannelActions(client)) - .setExecutor(client.getConfig().getExecutor()) - .setScheduler(client.getConfig().getScheduledExecutor()) - .setLoggerName(CHANNEL_FSM_LOGGER_NAME) - .build(); - - ChannelFsmFactory fsmFactory = new ChannelFsmFactory(fsmConfig); - - return fsmFactory.newChannelFsm(); - } - - private static class ClientChannelActions implements ChannelActions { - - private static final Logger LOGGER = LoggerFactory.getLogger(CHANNEL_FSM_LOGGER_NAME); - - private final UaStackClientConfig config; - private final UaStackClient client; - - ClientChannelActions(UaStackClient client) { - this.client = client; - this.config = client.getConfig(); - } - - @Override - public CompletableFuture connect(FsmContext ctx) { - CompletableFuture handshake = new CompletableFuture<>(); - - String transportProfileUri = config.getEndpoint().getTransportProfileUri(); - TransportProfile transportProfile = TransportProfile.fromUri(transportProfileUri); - - ChannelInitializer initializer; - - if (transportProfile == TransportProfile.TCP_UASC_UABINARY) { - initializer = new OpcClientTcpChannelInitializer(client, handshake); - } else { - initializer = new OpcClientWebSocketChannelInitializer(client, handshake); - } - - Bootstrap bootstrap = new Bootstrap(); - - bootstrap.group(config.getEventLoop()) - .channel(NioSocketChannel.class) - .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, config.getConnectTimeout().intValue()) - .option(ChannelOption.TCP_NODELAY, true) - .handler(initializer); - - try { - String endpointUrl = config.getEndpoint().getEndpointUrl(); - - String host = EndpointUtil.getHost(endpointUrl); - assert host != null; - - int port = EndpointUtil.getPort(endpointUrl); - - bootstrap.connect(host, port).addListener((ChannelFuture f) -> { - if (!f.isSuccess()) { - Throwable cause = f.cause(); - - if (cause instanceof ConnectTimeoutException) { - handshake.completeExceptionally( - new UaException(StatusCodes.Bad_Timeout, f.cause())); - } else if (cause instanceof ConnectException) { - handshake.completeExceptionally( - new UaException(StatusCodes.Bad_ConnectionRejected, f.cause())); - } else { - handshake.completeExceptionally(cause); - } - } - }); - } catch (Throwable e) { - UaException failure = new UaException( - StatusCodes.Bad_TcpEndpointUrlInvalid, e); - - handshake.completeExceptionally(failure); - } - - return handshake.thenApply(ClientSecureChannel::getChannel); - } - - @Override - public CompletableFuture disconnect(FsmContext ctx, Channel channel) { - CompletableFuture disconnectFuture = new CompletableFuture<>(); - - final TimerTask onTimeout = t -> channel.close().addListener( - (ChannelFutureListener) channelFuture -> - disconnectFuture.complete(null) - ); - - final Timeout timeout = config.getWheelTimer().newTimeout( - onTimeout, - 5, - TimeUnit.SECONDS - ); - - channel.pipeline().addFirst(new ChannelInboundHandlerAdapter() { - @Override - public void channelInactive(ChannelHandlerContext channelContext) throws Exception { - LOGGER.debug("[{}] channelInactive() disconnect complete", ctx.getInstanceId()); - timeout.cancel(); - disconnectFuture.complete(null); - super.channelInactive(channelContext); - } - }); - - RequestHeader requestHeader = new RequestHeader( - NodeId.NULL_VALUE, - DateTime.now(), - uint(0), - uint(0), - null, - uint(0), - null - ); - - LOGGER.debug("[{}] Sending CloseSecureChannelRequest...", ctx.getInstanceId()); - - channel.pipeline().fireUserEventTriggered( - new CloseSecureChannelRequest(requestHeader) - ); - - return disconnectFuture; - } - - @Override - public CompletableFuture keepAlive(FsmContext ctx, Channel channel) { - return CompletableFuture.completedFuture(null); - } - - } -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/UascClientMessageHandler.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/UascClientMessageHandler.java deleted file mode 100644 index 23f4e1bbe..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/UascClientMessageHandler.java +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.transport.uasc; - -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.CompositeByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageCodec; -import io.netty.util.ReferenceCountUtil; -import io.netty.util.Timeout; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.client.transport.UaTransportRequest; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.UaSerializationException; -import org.eclipse.milo.opcua.stack.core.UaServiceFaultException; -import org.eclipse.milo.opcua.stack.core.channel.ChannelSecurity; -import org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder; -import org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder.EncodedMessage; -import org.eclipse.milo.opcua.stack.core.channel.MessageAbortException; -import org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException; -import org.eclipse.milo.opcua.stack.core.channel.MessageEncodeException; -import org.eclipse.milo.opcua.stack.core.channel.SerializationQueue; -import org.eclipse.milo.opcua.stack.core.channel.headers.AsymmetricSecurityHeader; -import org.eclipse.milo.opcua.stack.core.channel.headers.HeaderDecoder; -import org.eclipse.milo.opcua.stack.core.channel.messages.ErrorMessage; -import org.eclipse.milo.opcua.stack.core.channel.messages.MessageType; -import org.eclipse.milo.opcua.stack.core.channel.messages.TcpMessageDecoder; -import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; -import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; -import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; -import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; -import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.core.types.enumerated.SecurityTokenRequestType; -import org.eclipse.milo.opcua.stack.core.types.structured.ChannelSecurityToken; -import org.eclipse.milo.opcua.stack.core.types.structured.CloseSecureChannelRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; -import org.eclipse.milo.opcua.stack.core.util.BufferUtil; -import org.eclipse.milo.opcua.stack.core.util.CertificateUtil; -import org.eclipse.milo.opcua.stack.core.util.LongSequence; -import org.eclipse.milo.opcua.stack.core.util.NonceUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - -public class UascClientMessageHandler extends ByteToMessageCodec implements HeaderDecoder { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private List chunkBuffers = new ArrayList<>(); - - private final AtomicReference headerRef = new AtomicReference<>(); - - private final Map pending = new ConcurrentHashMap<>(); - private final LongSequence requestIdSequence = new LongSequence(1L, UInteger.MAX_VALUE); - - private ScheduledFuture renewFuture; - private Timeout secureChannelTimeout; - private final int maxChunkCount; - private final int maxChunkSize; - - private final UaStackClientConfig config; - private final ClientSecureChannel secureChannel; - private final SerializationQueue serializationQueue; - private final CompletableFuture handshakeFuture; - - UascClientMessageHandler( - UaStackClientConfig config, - ClientSecureChannel secureChannel, - SerializationQueue serializationQueue, - CompletableFuture handshakeFuture) { - - this.config = config; - this.secureChannel = secureChannel; - this.serializationQueue = serializationQueue; - this.handshakeFuture = handshakeFuture; - - handshakeFuture.thenAccept(sc -> { - Channel channel = sc.getChannel(); - - channel.eventLoop().execute(() -> { - List awaitingHandshake = channel.attr( - UascClientAcknowledgeHandler.KEY_AWAITING_HANDSHAKE).get(); - - if (awaitingHandshake != null) { - channel.attr(UascClientAcknowledgeHandler.KEY_AWAITING_HANDSHAKE).set(null); - - logger.debug( - "{} message(s) queued before handshake completed; sending now.", - awaitingHandshake.size()); - - awaitingHandshake.forEach(channel::writeAndFlush); - } - }); - }); - - maxChunkCount = serializationQueue.getParameters().getLocalMaxChunkCount(); - maxChunkSize = serializationQueue.getParameters().getLocalReceiveBufferSize(); - } - - @Override - public void handlerAdded(ChannelHandlerContext ctx) { - SecurityTokenRequestType requestType = secureChannel.getChannelId() == 0 ? - SecurityTokenRequestType.Issue : SecurityTokenRequestType.Renew; - - secureChannelTimeout = config.getWheelTimer().newTimeout( - timeout -> { - if (!timeout.isCancelled()) { - handshakeFuture.completeExceptionally( - new UaException( - StatusCodes.Bad_Timeout, - "timed out waiting for secure channel")); - ctx.close(); - } - }, - config.getRequestTimeout().longValue(), TimeUnit.MILLISECONDS - ); - - logger.debug("OpenSecureChannel timeout scheduled for +{}ms", config.getRequestTimeout()); - - sendOpenSecureChannelRequest(ctx, requestType); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - if (renewFuture != null) renewFuture.cancel(false); - - UaException exception = new UaException( - StatusCodes.Bad_ConnectionClosed, - "connection closed" - ); - - handshakeFuture.completeExceptionally(exception); - - pending.values().forEach(request -> - request.getFuture() - .completeExceptionally(exception) - ); - - super.channelInactive(ctx); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - logger.error( - "[remote={}] Exception caught: {}", - ctx.channel().remoteAddress(), cause.getMessage(), cause); - - chunkBuffers.forEach(ReferenceCountUtil::safeRelease); - chunkBuffers.clear(); - - // If the handshake hasn't completed yet this cause will be more - // accurate than the generic "connection closed" exception that - // channelInactive() will use. - handshakeFuture.completeExceptionally(cause); - - ctx.close(); - } - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { - if (evt instanceof CloseSecureChannelRequest) { - sendCloseSecureChannelRequest(ctx, (CloseSecureChannelRequest) evt); - } - } - - private void sendOpenSecureChannelRequest(ChannelHandlerContext ctx, SecurityTokenRequestType requestType) { - ByteString clientNonce = secureChannel.isSymmetricSigningEnabled() ? - NonceUtil.generateNonce(secureChannel.getSecurityPolicy()) : - ByteString.NULL_VALUE; - - secureChannel.setLocalNonce(clientNonce); - - RequestHeader header = new RequestHeader( - null, - DateTime.now(), - uint(0), - uint(0), - null, - config.getRequestTimeout(), - null - ); - - OpenSecureChannelRequest request = new OpenSecureChannelRequest( - header, - uint(PROTOCOL_VERSION), - requestType, - secureChannel.getMessageSecurityMode(), - secureChannel.getLocalNonce(), - config.getChannelLifetime() - ); - - serializationQueue.encode((binaryEncoder, chunkEncoder) -> { - ByteBuf messageBuffer = BufferUtil.pooledBuffer(); - - try { - binaryEncoder.setBuffer(messageBuffer); - binaryEncoder.encodeMessage(null, request); - - checkMessageSize(messageBuffer); - - EncodedMessage encodedMessage = chunkEncoder.encodeAsymmetric( - secureChannel, - requestIdSequence.getAndIncrement(), - messageBuffer, - MessageType.OpenSecureChannel - ); - - CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); - - for (ByteBuf chunk : encodedMessage.getMessageChunks()) { - chunkComposite.addComponent(chunk); - chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); - } - - ctx.writeAndFlush(chunkComposite, ctx.voidPromise()); - - ChannelSecurity channelSecurity = secureChannel.getChannelSecurity(); - - long currentTokenId = -1L; - if (channelSecurity != null) { - currentTokenId = channelSecurity.getCurrentToken().getTokenId().longValue(); - } - - long previousTokenId = -1L; - if (channelSecurity != null) { - previousTokenId = channelSecurity.getPreviousToken() - .map(token -> token.getTokenId().longValue()) - .orElse(-1L); - } - - logger.debug( - "Sent OpenSecureChannelRequest ({}, id={}, currentToken={}, previousToken={}).", - request.getRequestType(), - secureChannel.getChannelId(), - currentTokenId, - previousTokenId - ); - } catch (MessageEncodeException e) { - logger.error("Error encoding {}: {}", request, e.getMessage(), e); - - ctx.close(); - } finally { - messageBuffer.release(); - } - }); - } - - private void checkMessageSize(ByteBuf messageBuffer) throws UaSerializationException { - int messageSize = messageBuffer.readableBytes(); - int remoteMaxMessageSize = serializationQueue.getParameters().getRemoteMaxMessageSize(); - - if (remoteMaxMessageSize > 0 && messageSize > remoteMaxMessageSize) { - throw new UaSerializationException( - StatusCodes.Bad_RequestTooLarge, - "request exceeds remote max message size: " + - messageSize + " > " + remoteMaxMessageSize); - } - } - - private void sendCloseSecureChannelRequest(ChannelHandlerContext ctx, CloseSecureChannelRequest request) { - serializationQueue.encode((binaryEncoder, chunkEncoder) -> { - ByteBuf messageBuffer = BufferUtil.pooledBuffer(); - - try { - binaryEncoder.setBuffer(messageBuffer); - binaryEncoder.encodeMessage(null, request); - - checkMessageSize(messageBuffer); - - EncodedMessage encodedMessage = chunkEncoder.encodeSymmetric( - secureChannel, - requestIdSequence.getAndIncrement(), - messageBuffer, - MessageType.CloseSecureChannel - ); - - CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); - - for (ByteBuf chunk : encodedMessage.getMessageChunks()) { - chunkComposite.addComponent(chunk); - chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); - } - - ctx.writeAndFlush(chunkComposite).addListener(future -> ctx.close()); - - secureChannel.setChannelId(0); - } catch (MessageEncodeException e) { - logger.error("Error encoding {}: {}", request, e.getMessage(), e); - handshakeFuture.completeExceptionally(e); - ctx.close(); - } catch (UaSerializationException e) { - logger.error("Error serializing {}: {}", request, e.getMessage(), e); - handshakeFuture.completeExceptionally(e); - ctx.close(); - } finally { - messageBuffer.release(); - } - }); - } - - @Override - protected void encode(ChannelHandlerContext ctx, UaTransportRequest request, ByteBuf buffer) { - serializationQueue.encode((binaryEncoder, chunkEncoder) -> { - ByteBuf messageBuffer = BufferUtil.pooledBuffer(); - - try { - binaryEncoder.setBuffer(messageBuffer); - binaryEncoder.encodeMessage(null, request.getRequest()); - - checkMessageSize(messageBuffer); - - EncodedMessage encodedMessage = chunkEncoder.encodeSymmetric( - secureChannel, - requestIdSequence.getAndIncrement(), - messageBuffer, - MessageType.SecureMessage - ); - - long requestId = encodedMessage.getRequestId(); - List messageChunks = encodedMessage.getMessageChunks(); - - pending.put(requestId, request); - - // No matter how we complete, make sure the entry in pending is removed. - // This covers the case where the request fails due to a timeout in the - // transport layer as well as normal completion. - request.getFuture().whenComplete((r, x) -> pending.remove(requestId)); - - CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); - - for (ByteBuf chunk : messageChunks) { - chunkComposite.addComponent(chunk); - chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); - } - - ctx.writeAndFlush(chunkComposite, ctx.voidPromise()); - } catch (MessageEncodeException e) { - logger.error("Error encoding {}: {}", request.getRequest(), e.getMessage(), e); - request.getFuture().completeExceptionally(e); - ctx.close(); - } catch (UaSerializationException e) { - logger.error("Error serializing {}: {}", request.getRequest(), e.getMessage(), e); - request.getFuture().completeExceptionally(e); - } finally { - messageBuffer.release(); - } - }); - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { - if (buffer.readableBytes() >= HEADER_LENGTH) { - int messageLength = getMessageLength(buffer, maxChunkSize); - - if (buffer.readableBytes() >= messageLength) { - decodeMessage(ctx, buffer, messageLength); - } - } - } - - private void decodeMessage(ChannelHandlerContext ctx, ByteBuf buffer, int messageLength) throws UaException { - MessageType messageType = MessageType.fromMediumInt( - buffer.getMediumLE(buffer.readerIndex()) - ); - - switch (messageType) { - case OpenSecureChannel: - onOpenSecureChannel(ctx, buffer.readSlice(messageLength)); - break; - - case SecureMessage: - onSecureMessage(ctx, buffer.readSlice(messageLength)); - break; - - case Error: - onError(ctx, buffer.readSlice(messageLength)); - break; - - default: - throw new UaException( - StatusCodes.Bad_TcpMessageTypeInvalid, - "unexpected MessageType: " + messageType - ); - } - } - - private boolean accumulateChunk(ByteBuf buffer) throws UaException { - int chunkSize = buffer.readerIndex(0).readableBytes(); - - if (chunkSize > maxChunkSize) { - throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, - String.format("max chunk size exceeded (%s)", maxChunkSize)); - } - - chunkBuffers.add(buffer.retain()); - - if (maxChunkCount > 0 && chunkBuffers.size() > maxChunkCount) { - throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, - String.format("max chunk count exceeded (%s)", maxChunkCount)); - } - - char chunkType = (char) buffer.getByte(3); - - return (chunkType == 'A' || chunkType == 'F'); - } - - private void onOpenSecureChannel(ChannelHandlerContext ctx, ByteBuf buffer) throws UaException { - if (secureChannelTimeout != null) { - if (secureChannelTimeout.cancel()) { - logger.debug("OpenSecureChannel timeout canceled"); - - secureChannelTimeout = null; - } else { - logger.warn("timed out waiting for secure channel"); - - handshakeFuture.completeExceptionally( - new UaException(StatusCodes.Bad_Timeout, - "timed out waiting for secure channel")); - ctx.close(); - return; - } - } - - buffer.skipBytes(3 + 1 + 4 + 4); // skip messageType, chunkType, messageSize, secureChannelId - - AsymmetricSecurityHeader securityHeader = AsymmetricSecurityHeader.decode( - buffer, - config.getEncodingLimits() - ); - - if (headerRef.compareAndSet(null, securityHeader)) { - // first time we've received the header; validate and verify the server certificate - CertificateValidator certificateValidator = config.getCertificateValidator(); - - SecurityPolicy securityPolicy = SecurityPolicy.fromUri(securityHeader.getSecurityPolicyUri()); - - if (securityPolicy != SecurityPolicy.None) { - ByteString serverCertificateBytes = securityHeader.getSenderCertificate(); - - List serverCertificateChain = - CertificateUtil.decodeCertificates(serverCertificateBytes.bytesOrEmpty()); - - certificateValidator.validateCertificateChain(serverCertificateChain); - } - } else { - if (!securityHeader.equals(headerRef.get())) { - throw new UaException(StatusCodes.Bad_SecurityChecksFailed, - "subsequent AsymmetricSecurityHeader did not match"); - } - } - - if (accumulateChunk(buffer)) { - final List buffersToDecode = chunkBuffers; - chunkBuffers = new ArrayList<>(maxChunkCount); - - serializationQueue.decode((binaryDecoder, chunkDecoder) -> { - ByteBuf message; - - try { - ChunkDecoder.DecodedMessage decodedMessage = - chunkDecoder.decodeAsymmetric(secureChannel, buffersToDecode); - - message = decodedMessage.getMessage(); - } catch (MessageAbortException e) { - logger.warn( - "Received message abort chunk; error={}, reason={}", - e.getStatusCode(), e.getMessage() - ); - return; - } catch (MessageDecodeException e) { - logger.error("Error decoding asymmetric message", e); - - handshakeFuture.completeExceptionally(e); - - ctx.close(); - return; - } - - try { - UaResponseMessageType response = (UaResponseMessageType) binaryDecoder - .setBuffer(message) - .decodeMessage(null); - - StatusCode serviceResult = response.getResponseHeader().getServiceResult(); - - if (serviceResult.isGood()) { - OpenSecureChannelResponse oscr = (OpenSecureChannelResponse) response; - - secureChannel.setChannelId(oscr.getSecurityToken().getChannelId().longValue()); - logger.debug("Received OpenSecureChannelResponse."); - - installSecurityToken(ctx, oscr); - - handshakeFuture.complete(secureChannel); - } else { - ServiceFault serviceFault = (response instanceof ServiceFault) ? - (ServiceFault) response : new ServiceFault(response.getResponseHeader()); - - handshakeFuture.completeExceptionally(new UaServiceFaultException(serviceFault)); - ctx.close(); - } - } catch (Throwable t) { - logger.error("Error decoding OpenSecureChannelResponse", t); - - handshakeFuture.completeExceptionally(t); - ctx.close(); - } finally { - message.release(); - } - }); - } - } - - private void installSecurityToken( - ChannelHandlerContext ctx, - OpenSecureChannelResponse response - ) throws UaException { - - if (response.getServerProtocolVersion().longValue() < PROTOCOL_VERSION) { - throw new UaException(StatusCodes.Bad_ProtocolVersionUnsupported, - "server protocol version unsupported: " + response.getServerProtocolVersion()); - } - - ChannelSecurity.SecurityKeys newKeys = null; - ChannelSecurityToken newToken = response.getSecurityToken(); - - if (secureChannel.isSymmetricSigningEnabled()) { - ByteString serverNonce = response.getServerNonce(); - - NonceUtil.validateNonce(serverNonce, secureChannel.getSecurityPolicy()); - - secureChannel.setRemoteNonce(serverNonce); - - newKeys = ChannelSecurity.generateKeyPair( - secureChannel, - secureChannel.getLocalNonce(), - secureChannel.getRemoteNonce() - ); - } - - ChannelSecurity oldSecrets = secureChannel.getChannelSecurity(); - ChannelSecurity.SecurityKeys oldKeys = oldSecrets != null ? oldSecrets.getCurrentKeys() : null; - ChannelSecurityToken oldToken = oldSecrets != null ? oldSecrets.getCurrentToken() : null; - - secureChannel.setChannelSecurity(new ChannelSecurity(newKeys, newToken, oldKeys, oldToken)); - - DateTime createdAt = response.getSecurityToken().getCreatedAt(); - long revisedLifetime = response.getSecurityToken().getRevisedLifetime().longValue(); - - if (revisedLifetime > 0) { - long renewAt = (long) (revisedLifetime * 0.75); - renewFuture = ctx.executor().schedule( - () -> sendOpenSecureChannelRequest(ctx, SecurityTokenRequestType.Renew), - renewAt, TimeUnit.MILLISECONDS); - } else { - logger.warn("Server revised secure channel lifetime to 0; renewal will not occur."); - } - - ctx.executor().execute(() -> { - // SecureChannel is ready; remove the acknowledge handler. - if (ctx.pipeline().get(UascClientAcknowledgeHandler.class) != null) { - ctx.pipeline().remove(UascClientAcknowledgeHandler.class); - } - }); - - ChannelSecurity channelSecurity = secureChannel.getChannelSecurity(); - - long currentTokenId = channelSecurity.getCurrentToken().getTokenId().longValue(); - - long previousTokenId = channelSecurity.getPreviousToken() - .map(t -> t.getTokenId().longValue()).orElse(-1L); - - logger.debug( - "SecureChannel id={}, currentTokenId={}, previousTokenId={}, lifetime={}ms, createdAt={}", - secureChannel.getChannelId(), currentTokenId, previousTokenId, revisedLifetime, createdAt); - } - - private void onSecureMessage(ChannelHandlerContext ctx, ByteBuf buffer) throws UaException { - buffer.skipBytes(3 + 1 + 4); // skip messageType, chunkType, messageSize - - long secureChannelId = buffer.readUnsignedIntLE(); - if (secureChannelId != secureChannel.getChannelId()) { - throw new UaException(StatusCodes.Bad_SecureChannelIdInvalid, - "invalid secure channel id: " + secureChannelId); - } - - if (accumulateChunk(buffer)) { - final List buffersToDecode = chunkBuffers; - chunkBuffers = new ArrayList<>(maxChunkCount); - - serializationQueue.decode((binaryDecoder, chunkDecoder) -> { - ByteBuf message; - long requestId; - - try { - ChunkDecoder.DecodedMessage decodedMessage = - chunkDecoder.decodeSymmetric(secureChannel, buffersToDecode); - - message = decodedMessage.getMessage(); - requestId = decodedMessage.getRequestId(); - } catch (MessageAbortException e) { - logger.warn( - "Received message abort chunk; error={}, reason={}", - e.getStatusCode(), e.getMessage() - ); - - UaTransportRequest request = pending.remove(e.getRequestId()); - - if (request != null) { - request.getFuture().completeExceptionally(e); - } else { - logger.warn("No pending request for requestId={}", e.getRequestId()); - } - return; - } catch (MessageDecodeException e) { - logger.error("Error decoding symmetric message", e); - - ctx.close(); - return; - } - - - UaTransportRequest request = pending.remove(requestId); - - try { - UaResponseMessageType response = (UaResponseMessageType) binaryDecoder - .setBuffer(message) - .decodeMessage(null); - - if (request != null) { - request.getFuture().complete(response); - } else { - logger.warn( - "No pending request with requestId={} for {}", - requestId, response.getClass().getSimpleName() - ); - } - } catch (Throwable t) { - logger.error("Error decoding UaResponseMessage", t); - - if (request != null) { - request.getFuture().completeExceptionally(t); - } - } finally { - message.release(); - } - }); - } - } - - private void onError(ChannelHandlerContext ctx, ByteBuf buffer) { - try { - ErrorMessage errorMessage = TcpMessageDecoder.decodeError(buffer); - StatusCode statusCode = errorMessage.getError(); - - logger.error("[remote={}] errorMessage={}", ctx.channel().remoteAddress(), errorMessage); - - handshakeFuture.completeExceptionally(new UaException(statusCode, errorMessage.getReason())); - } catch (UaException e) { - logger.error( - "[remote={}] An exception occurred while decoding an error message: {}", - ctx.channel().remoteAddress(), e.getMessage(), e); - - handshakeFuture.completeExceptionally(e); - } finally { - ctx.close(); - } - } - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/websocket/OpcClientWebSocketChannelInitializer.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/websocket/OpcClientWebSocketChannelInitializer.java deleted file mode 100644 index a3d8cdfce..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/websocket/OpcClientWebSocketChannelInitializer.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.transport.websocket; - -import java.net.URI; -import java.util.concurrent.CompletableFuture; - -import io.netty.channel.ChannelInitializer; -import io.netty.channel.socket.SocketChannel; -import io.netty.handler.codec.http.DefaultHttpHeaders; -import io.netty.handler.codec.http.HttpClientCodec; -import io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory; -import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler; -import io.netty.handler.codec.http.websocketx.WebSocketFrameAggregator; -import io.netty.handler.codec.http.websocketx.WebSocketVersion; -import io.netty.handler.logging.LogLevel; -import io.netty.handler.logging.LoggingHandler; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; -import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; - -public class OpcClientWebSocketChannelInitializer extends ChannelInitializer { - - private final UaStackClient client; - private final CompletableFuture handshake; - - public OpcClientWebSocketChannelInitializer( - UaStackClient client, - CompletableFuture handshake) { - - this.client = client; - this.handshake = handshake; - } - - @Override - protected void initChannel(SocketChannel channel) throws Exception { - String endpointUrl = client.getConfig().getEndpoint().getEndpointUrl(); - String scheme = EndpointUtil.getScheme(endpointUrl); - - TransportProfile transportProfile = TransportProfile - .fromUri(client.getConfig().getEndpoint().getTransportProfileUri()); - - String subprotocol; - if (transportProfile == TransportProfile.WSS_UASC_UABINARY) { - subprotocol = "opcua+cp"; - } else if (transportProfile == TransportProfile.WSS_UAJSON) { - subprotocol = "opcua+uajson"; - } else { - throw new UaException( - StatusCodes.Bad_InternalError, - "unexpected TransportProfile: " + transportProfile); - } - - if ("opc.wss".equalsIgnoreCase(scheme)) { - SslContext sslContext = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .build(); - - channel.pipeline().addLast(sslContext.newHandler(channel.alloc())); - } - - int maxMessageSize = client.getConfig().getEncodingLimits().getMaxMessageSize(); - - channel.pipeline().addLast(new LoggingHandler(LogLevel.INFO)); - channel.pipeline().addLast(new HttpClientCodec()); - channel.pipeline().addLast(new HttpObjectAggregator(maxMessageSize)); - - channel.pipeline().addLast( - new WebSocketClientProtocolHandler( - WebSocketClientHandshakerFactory.newHandshaker( - new URI(endpointUrl), - WebSocketVersion.V13, - subprotocol, - true, - new DefaultHttpHeaders(), - client.getConfig().getEncodingLimits().getMaxChunkSize() - ) - ) - ); - - channel.pipeline().addLast( - new WebSocketFrameAggregator( - client.getConfig().getEncodingLimits().getMaxMessageSize()) - ); - - // OpcClientWebSocketFrameCodec adds UascClientAcknowledgeHandler when the WS upgrade is done. - channel.pipeline().addLast(new OpcClientWebSocketBinaryFrameCodec(client, handshake)); - } - -} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/websocket/OpcWebSocketTransport.java b/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/websocket/OpcWebSocketTransport.java deleted file mode 100644 index 08b46c6e2..000000000 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/websocket/OpcWebSocketTransport.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2021 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.transport.websocket; - -import java.util.concurrent.CompletableFuture; - -import com.digitalpetri.netty.fsm.ChannelFsm; -import io.netty.channel.Channel; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.client.transport.AbstractTransport; -import org.eclipse.milo.opcua.stack.client.transport.UaTransport; -import org.eclipse.milo.opcua.stack.client.transport.uasc.ClientChannelFsm; - -public class OpcWebSocketTransport extends AbstractTransport { - - private final ChannelFsm channelFsm; - - private final UaStackClient client; - - public OpcWebSocketTransport(UaStackClient client) { - super(client.getConfig()); - - this.client = client; - - channelFsm = ClientChannelFsm.newChannelFsm(client); - } - - @Override - public UaStackClientConfig getConfig() { - return client.getConfig(); - } - - @Override - public CompletableFuture connect() { - return channelFsm.connect() - .thenApply(v -> OpcWebSocketTransport.this); - } - - @Override - public CompletableFuture disconnect() { - return channelFsm.disconnect() - .thenApply(v -> OpcWebSocketTransport.this); - } - - @Override - public CompletableFuture channel() { - return channelFsm.getChannel(); - } - -} diff --git a/opc-ua-stack/stack-client/src/main/resources/example-keystore.pfx b/opc-ua-stack/stack-client/src/main/resources/example-keystore.pfx deleted file mode 100644 index 71c881206..000000000 Binary files a/opc-ua-stack/stack-client/src/main/resources/example-keystore.pfx and /dev/null differ diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/security/ClientCertificateValidator.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/ClientCertificateValidator.java similarity index 89% rename from opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/security/ClientCertificateValidator.java rename to opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/ClientCertificateValidator.java index e74a85c58..312d95cb6 100644 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/security/ClientCertificateValidator.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/ClientCertificateValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,13 +8,12 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.client.security; +package org.eclipse.milo.opcua.stack.core.security; import java.security.cert.X509Certificate; import java.util.List; import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/security/DefaultClientCertificateValidator.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/DefaultClientCertificateValidator.java similarity index 96% rename from opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/security/DefaultClientCertificateValidator.java rename to opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/DefaultClientCertificateValidator.java index fa2fbee40..63bd975fa 100644 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/security/DefaultClientCertificateValidator.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/DefaultClientCertificateValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.client.security; +package org.eclipse.milo.opcua.stack.core.security; import java.security.cert.PKIXCertPathBuilderResult; import java.security.cert.X509CRL; @@ -18,7 +18,6 @@ import java.util.Set; import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.security.TrustListManager; import org.eclipse.milo.opcua.stack.core.util.validation.CertificateValidationUtil; import org.eclipse.milo.opcua.stack.core.util.validation.ValidationCheck; import org.slf4j.Logger; diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/security/DefaultServerCertificateValidator.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/DefaultServerCertificateValidator.java similarity index 96% rename from opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/security/DefaultServerCertificateValidator.java rename to opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/DefaultServerCertificateValidator.java index a0cb8da87..187156f3c 100644 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/security/DefaultServerCertificateValidator.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/DefaultServerCertificateValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.server.security; +package org.eclipse.milo.opcua.stack.core.security; import java.security.cert.PKIXCertPathBuilderResult; import java.security.cert.X509CRL; @@ -19,7 +19,6 @@ import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.security.TrustListManager; import org.eclipse.milo.opcua.stack.core.util.validation.CertificateValidationUtil; import org.eclipse.milo.opcua.stack.core.util.validation.ValidationCheck; import org.slf4j.Logger; diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/security/ServerCertificateValidator.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/ServerCertificateValidator.java similarity index 76% rename from opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/security/ServerCertificateValidator.java rename to opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/ServerCertificateValidator.java index 020ad2c01..b02969620 100644 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/security/ServerCertificateValidator.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/security/ServerCertificateValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,13 +8,12 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.server.security; +package org.eclipse.milo.opcua.stack.core.security; import java.security.cert.X509Certificate; import java.util.List; import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; public interface ServerCertificateValidator extends CertificateValidator { diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/DataTypeInitializer.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/DataTypeInitializer.java index c68174bf8..6421a787a 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/DataTypeInitializer.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/DataTypeInitializer.java @@ -213,6 +213,8 @@ import org.eclipse.milo.opcua.stack.core.types.structured.ReceiveQosPriorityDataType; import org.eclipse.milo.opcua.stack.core.types.structured.RedundantServerDataType; import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceDescriptionDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceListEntryDataType; import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceNode; import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceTypeAttributes; import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceTypeNode; @@ -268,6 +270,7 @@ import org.eclipse.milo.opcua.stack.core.types.structured.ThreeDOrientation; import org.eclipse.milo.opcua.stack.core.types.structured.ThreeDVector; import org.eclipse.milo.opcua.stack.core.types.structured.TimeZoneDataType; +import org.eclipse.milo.opcua.stack.core.types.structured.TransactionErrorType; import org.eclipse.milo.opcua.stack.core.types.structured.TransferResult; import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsRequest; import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsResponse; @@ -303,7 +306,6 @@ import org.eclipse.milo.opcua.stack.core.types.structured.X509IdentityToken; import org.eclipse.milo.opcua.stack.core.types.structured.XVType; -// TODO regenerate public class DataTypeInitializer { public void initialize(NamespaceTable namespaceTable, DataTypeManager dataTypeManager) { try { @@ -392,6 +394,13 @@ private void registerStructCodecs(NamespaceTable namespaceTable, DataTypeManager TrustListDataType.XML_ENCODING_ID.toNodeIdOrThrow(namespaceTable), TrustListDataType.JSON_ENCODING_ID.toNodeIdOrThrow(namespaceTable) ); + dataTypeManager.registerType( + TransactionErrorType.TYPE_ID.toNodeIdOrThrow(namespaceTable), + new TransactionErrorType.Codec(), + TransactionErrorType.BINARY_ENCODING_ID.toNodeIdOrThrow(namespaceTable), + TransactionErrorType.XML_ENCODING_ID.toNodeIdOrThrow(namespaceTable), + TransactionErrorType.JSON_ENCODING_ID.toNodeIdOrThrow(namespaceTable) + ); dataTypeManager.registerType( UABinaryFileDataType.TYPE_ID.toNodeIdOrThrow(namespaceTable), new UABinaryFileDataType.Codec(), @@ -756,6 +765,20 @@ private void registerStructCodecs(NamespaceTable namespaceTable, DataTypeManager PriorityMappingEntryType.XML_ENCODING_ID.toNodeIdOrThrow(namespaceTable), PriorityMappingEntryType.JSON_ENCODING_ID.toNodeIdOrThrow(namespaceTable) ); + dataTypeManager.registerType( + ReferenceDescriptionDataType.TYPE_ID.toNodeIdOrThrow(namespaceTable), + new ReferenceDescriptionDataType.Codec(), + ReferenceDescriptionDataType.BINARY_ENCODING_ID.toNodeIdOrThrow(namespaceTable), + ReferenceDescriptionDataType.XML_ENCODING_ID.toNodeIdOrThrow(namespaceTable), + ReferenceDescriptionDataType.JSON_ENCODING_ID.toNodeIdOrThrow(namespaceTable) + ); + dataTypeManager.registerType( + ReferenceListEntryDataType.TYPE_ID.toNodeIdOrThrow(namespaceTable), + new ReferenceListEntryDataType.Codec(), + ReferenceListEntryDataType.BINARY_ENCODING_ID.toNodeIdOrThrow(namespaceTable), + ReferenceListEntryDataType.XML_ENCODING_ID.toNodeIdOrThrow(namespaceTable), + ReferenceListEntryDataType.JSON_ENCODING_ID.toNodeIdOrThrow(namespaceTable) + ); dataTypeManager.registerType( RolePermissionType.TYPE_ID.toNodeIdOrThrow(namespaceTable), new RolePermissionType.Codec(), @@ -2353,5 +2376,4 @@ private void registerStructCodecs(NamespaceTable namespaceTable, DataTypeManager DeleteSubscriptionsResponse.JSON_ENCODING_ID.toNodeIdOrThrow(namespaceTable) ); } - } diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessLevelExType.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessLevelExType.java index ed1264777..73fa0b220 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessLevelExType.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessLevelExType.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -89,13 +90,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static AccessLevelExType of(Field... fields) { + public static AccessLevelExType of(AccessLevelExType.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -105,7 +106,7 @@ public static AccessLevelExType of(Field... fields) { return new AccessLevelExType(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { CurrentRead(0), CurrentWrite(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessLevelType.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessLevelType.java index 120b99746..c5dafa2a6 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessLevelType.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessLevelType.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI8; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; /** @@ -65,13 +66,13 @@ public UByte getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static AccessLevelType of(Field... fields) { + public static AccessLevelType of(AccessLevelType.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -81,7 +82,7 @@ public static AccessLevelType of(Field... fields) { return new AccessLevelType(UByte.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { CurrentRead(0), CurrentWrite(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessRestrictionType.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessRestrictionType.java index e39b4a20b..ed0850120 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessRestrictionType.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AccessRestrictionType.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI16; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; /** @@ -53,13 +54,13 @@ public UShort getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static AccessRestrictionType of(Field... fields) { + public static AccessRestrictionType of(AccessRestrictionType.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -69,7 +70,7 @@ public static AccessRestrictionType of(Field... fields) { return new AccessRestrictionType(UShort.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { SigningRequired(0), EncryptionRequired(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AlarmMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AlarmMask.java new file mode 100644 index 000000000..2f4741f8c --- /dev/null +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AlarmMask.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.core.types.structured; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI16; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part9/8.3 + */ +@EqualsAndHashCode( + callSuper = true +) +@ToString +public class AlarmMask extends OptionSetUI16 { + public AlarmMask(UShort value) { + super(value); + } + + public boolean getActive() { + return get(Field.Active); + } + + public boolean getUnacknowledged() { + return get(Field.Unacknowledged); + } + + public boolean getUnconfirmed() { + return get(Field.Unconfirmed); + } + + @Override + public UShort getValue() { + return (UShort) value; + } + + @Override + public Set toSet() { + return Arrays.stream(Field.values()) + .filter(this::get) + .collect(Collectors.toSet()); + } + + public static AlarmMask of(AlarmMask.Field... fields) { + long bits = 0L; + + for (Field f : fields) { + bits |= (1L << f.bitIndex); + } + + return new AlarmMask(UShort.valueOf(bits)); + } + + public enum Field implements OptionSetUInteger.BitIndex { + Active(0), + + Unacknowledged(1), + + Unconfirmed(2); + + private final int bitIndex; + + Field(int bitIndex) { + this.bitIndex = bitIndex; + } + + @Override + public int getBitIndex() { + return bitIndex; + } + } +} diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AttributeWriteMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AttributeWriteMask.java index 5ed0d3964..4d0d5d198 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AttributeWriteMask.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/AttributeWriteMask.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -141,13 +142,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static AttributeWriteMask of(Field... fields) { + public static AttributeWriteMask of(AttributeWriteMask.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -157,7 +158,7 @@ public static AttributeWriteMask of(Field... fields) { return new AttributeWriteMask(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { AccessLevel(0), ArrayDimensions(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/DataSetFieldContentMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/DataSetFieldContentMask.java index 4fc846a6e..cd196ca44 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/DataSetFieldContentMask.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/DataSetFieldContentMask.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -61,13 +62,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static DataSetFieldContentMask of(Field... fields) { + public static DataSetFieldContentMask of(DataSetFieldContentMask.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -77,7 +78,7 @@ public static DataSetFieldContentMask of(Field... fields) { return new DataSetFieldContentMask(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { StatusCode(0), SourceTimestamp(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/DataSetFieldFlags.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/DataSetFieldFlags.java index cc2c447a2..279c1fc87 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/DataSetFieldFlags.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/DataSetFieldFlags.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI16; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort; /** @@ -41,13 +42,13 @@ public UShort getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static DataSetFieldFlags of(Field... fields) { + public static DataSetFieldFlags of(DataSetFieldFlags.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -57,7 +58,7 @@ public static DataSetFieldFlags of(Field... fields) { return new DataSetFieldFlags(UShort.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { PromotedField(0); private final int bitIndex; diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/EventNotifierType.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/EventNotifierType.java index eb028ec3d..404305bde 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/EventNotifierType.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/EventNotifierType.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI8; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte; /** @@ -49,13 +50,13 @@ public UByte getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static EventNotifierType of(Field... fields) { + public static EventNotifierType of(EventNotifierType.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -65,7 +66,7 @@ public static EventNotifierType of(Field... fields) { return new EventNotifierType(UByte.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { SubscribeToEvents(0), HistoryRead(2), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/JsonDataSetMessageContentMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/JsonDataSetMessageContentMask.java index 1a5a93594..eeddd9813 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/JsonDataSetMessageContentMask.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/JsonDataSetMessageContentMask.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -69,13 +70,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static JsonDataSetMessageContentMask of(Field... fields) { + public static JsonDataSetMessageContentMask of(JsonDataSetMessageContentMask.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -85,7 +86,7 @@ public static JsonDataSetMessageContentMask of(Field... fields) { return new JsonDataSetMessageContentMask(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { DataSetWriterId(0), MetaDataVersion(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/JsonNetworkMessageContentMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/JsonNetworkMessageContentMask.java index ec8a6e849..cc1e4417e 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/JsonNetworkMessageContentMask.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/JsonNetworkMessageContentMask.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -61,13 +62,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static JsonNetworkMessageContentMask of(Field... fields) { + public static JsonNetworkMessageContentMask of(JsonNetworkMessageContentMask.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -77,7 +78,7 @@ public static JsonNetworkMessageContentMask of(Field... fields) { return new JsonNetworkMessageContentMask(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { NetworkMessageHeader(0), DataSetMessageHeader(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PasswordOptionsMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PasswordOptionsMask.java index ba8779792..ef6aaf1d5 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PasswordOptionsMask.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PasswordOptionsMask.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -73,13 +74,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static PasswordOptionsMask of(Field... fields) { + public static PasswordOptionsMask of(PasswordOptionsMask.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -89,7 +90,7 @@ public static PasswordOptionsMask of(Field... fields) { return new PasswordOptionsMask(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { SupportInitialPasswordChange(0), SupportDisableUser(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PermissionType.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PermissionType.java index cfde776b7..35eca968a 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PermissionType.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PermissionType.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -105,13 +106,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static PermissionType of(Field... fields) { + public static PermissionType of(PermissionType.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -121,7 +122,7 @@ public static PermissionType of(Field... fields) { return new PermissionType(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { Browse(0), ReadRolePermissions(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PubSubConfigurationRefMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PubSubConfigurationRefMask.java index f18d6cdcd..9267406a1 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PubSubConfigurationRefMask.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/PubSubConfigurationRefMask.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -89,13 +90,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static PubSubConfigurationRefMask of(Field... fields) { + public static PubSubConfigurationRefMask of(PubSubConfigurationRefMask.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -105,7 +106,7 @@ public static PubSubConfigurationRefMask of(Field... fields) { return new PubSubConfigurationRefMask(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { ElementAdd(0), ElementMatch(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/ReferenceDescriptionDataType.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/ReferenceDescriptionDataType.java new file mode 100644 index 000000000..ef0e62014 --- /dev/null +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/ReferenceDescriptionDataType.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.core.types.structured; + +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import org.eclipse.milo.opcua.stack.core.NamespaceTable; +import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; +import org.eclipse.milo.opcua.stack.core.encoding.GenericDataTypeCodec; +import org.eclipse.milo.opcua.stack.core.encoding.UaDecoder; +import org.eclipse.milo.opcua.stack.core.encoding.UaEncoder; +import org.eclipse.milo.opcua.stack.core.types.UaStructuredType; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.StructureType; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part23/5.5.1 + */ +@EqualsAndHashCode( + callSuper = false +) +@SuperBuilder +@ToString +public class ReferenceDescriptionDataType extends Structure implements UaStructuredType { + public static final ExpandedNodeId TYPE_ID = ExpandedNodeId.parse("ns=0;i=32659"); + + public static final ExpandedNodeId BINARY_ENCODING_ID = ExpandedNodeId.parse("i=32661"); + + public static final ExpandedNodeId XML_ENCODING_ID = ExpandedNodeId.parse("i=32669"); + + public static final ExpandedNodeId JSON_ENCODING_ID = ExpandedNodeId.parse("i=32677"); + + private final NodeId sourceNode; + + private final NodeId referenceType; + + private final Boolean isForward; + + private final ExpandedNodeId targetNode; + + public ReferenceDescriptionDataType(NodeId sourceNode, NodeId referenceType, Boolean isForward, + ExpandedNodeId targetNode) { + this.sourceNode = sourceNode; + this.referenceType = referenceType; + this.isForward = isForward; + this.targetNode = targetNode; + } + + @Override + public ExpandedNodeId getTypeId() { + return TYPE_ID; + } + + @Override + public ExpandedNodeId getBinaryEncodingId() { + return BINARY_ENCODING_ID; + } + + @Override + public ExpandedNodeId getXmlEncodingId() { + return XML_ENCODING_ID; + } + + @Override + public ExpandedNodeId getJsonEncodingId() { + return JSON_ENCODING_ID; + } + + public NodeId getSourceNode() { + return sourceNode; + } + + public NodeId getReferenceType() { + return referenceType; + } + + public Boolean getIsForward() { + return isForward; + } + + public ExpandedNodeId getTargetNode() { + return targetNode; + } + + public static StructureDefinition definition(NamespaceTable namespaceTable) { + return new StructureDefinition( + new NodeId(0, 32661), + new NodeId(0, 22), + StructureType.Structure, + new StructureField[]{ + new StructureField("SourceNode", LocalizedText.NULL_VALUE, new NodeId(0, 17), -1, null, UInteger.valueOf(0), false), + new StructureField("ReferenceType", LocalizedText.NULL_VALUE, new NodeId(0, 17), -1, null, UInteger.valueOf(0), false), + new StructureField("IsForward", LocalizedText.NULL_VALUE, new NodeId(0, 1), -1, null, UInteger.valueOf(0), false), + new StructureField("TargetNode", LocalizedText.NULL_VALUE, new NodeId(0, 18), -1, null, UInteger.valueOf(0), false) + } + ); + } + + public static final class Codec extends GenericDataTypeCodec { + @Override + public Class getType() { + return ReferenceDescriptionDataType.class; + } + + @Override + public ReferenceDescriptionDataType decodeType(EncodingContext context, UaDecoder decoder) { + NodeId sourceNode = decoder.decodeNodeId("SourceNode"); + NodeId referenceType = decoder.decodeNodeId("ReferenceType"); + Boolean isForward = decoder.decodeBoolean("IsForward"); + ExpandedNodeId targetNode = decoder.decodeExpandedNodeId("TargetNode"); + return new ReferenceDescriptionDataType(sourceNode, referenceType, isForward, targetNode); + } + + @Override + public void encodeType(EncodingContext context, UaEncoder encoder, + ReferenceDescriptionDataType value) { + encoder.encodeNodeId("SourceNode", value.getSourceNode()); + encoder.encodeNodeId("ReferenceType", value.getReferenceType()); + encoder.encodeBoolean("IsForward", value.getIsForward()); + encoder.encodeExpandedNodeId("TargetNode", value.getTargetNode()); + } + } +} diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/ReferenceListEntryDataType.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/ReferenceListEntryDataType.java new file mode 100644 index 000000000..af54c810c --- /dev/null +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/ReferenceListEntryDataType.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.core.types.structured; + +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import org.eclipse.milo.opcua.stack.core.NamespaceTable; +import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; +import org.eclipse.milo.opcua.stack.core.encoding.GenericDataTypeCodec; +import org.eclipse.milo.opcua.stack.core.encoding.UaDecoder; +import org.eclipse.milo.opcua.stack.core.encoding.UaEncoder; +import org.eclipse.milo.opcua.stack.core.types.UaStructuredType; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.StructureType; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part23/5.5.2 + */ +@EqualsAndHashCode( + callSuper = false +) +@SuperBuilder +@ToString +public class ReferenceListEntryDataType extends Structure implements UaStructuredType { + public static final ExpandedNodeId TYPE_ID = ExpandedNodeId.parse("ns=0;i=32660"); + + public static final ExpandedNodeId BINARY_ENCODING_ID = ExpandedNodeId.parse("i=32662"); + + public static final ExpandedNodeId XML_ENCODING_ID = ExpandedNodeId.parse("i=32670"); + + public static final ExpandedNodeId JSON_ENCODING_ID = ExpandedNodeId.parse("i=32678"); + + private final NodeId referenceType; + + private final Boolean isForward; + + private final ExpandedNodeId targetNode; + + public ReferenceListEntryDataType(NodeId referenceType, Boolean isForward, + ExpandedNodeId targetNode) { + this.referenceType = referenceType; + this.isForward = isForward; + this.targetNode = targetNode; + } + + @Override + public ExpandedNodeId getTypeId() { + return TYPE_ID; + } + + @Override + public ExpandedNodeId getBinaryEncodingId() { + return BINARY_ENCODING_ID; + } + + @Override + public ExpandedNodeId getXmlEncodingId() { + return XML_ENCODING_ID; + } + + @Override + public ExpandedNodeId getJsonEncodingId() { + return JSON_ENCODING_ID; + } + + public NodeId getReferenceType() { + return referenceType; + } + + public Boolean getIsForward() { + return isForward; + } + + public ExpandedNodeId getTargetNode() { + return targetNode; + } + + public static StructureDefinition definition(NamespaceTable namespaceTable) { + return new StructureDefinition( + new NodeId(0, 32662), + new NodeId(0, 22), + StructureType.Structure, + new StructureField[]{ + new StructureField("ReferenceType", LocalizedText.NULL_VALUE, new NodeId(0, 17), -1, null, UInteger.valueOf(0), false), + new StructureField("IsForward", LocalizedText.NULL_VALUE, new NodeId(0, 1), -1, null, UInteger.valueOf(0), false), + new StructureField("TargetNode", LocalizedText.NULL_VALUE, new NodeId(0, 18), -1, null, UInteger.valueOf(0), false) + } + ); + } + + public static final class Codec extends GenericDataTypeCodec { + @Override + public Class getType() { + return ReferenceListEntryDataType.class; + } + + @Override + public ReferenceListEntryDataType decodeType(EncodingContext context, UaDecoder decoder) { + NodeId referenceType = decoder.decodeNodeId("ReferenceType"); + Boolean isForward = decoder.decodeBoolean("IsForward"); + ExpandedNodeId targetNode = decoder.decodeExpandedNodeId("TargetNode"); + return new ReferenceListEntryDataType(referenceType, isForward, targetNode); + } + + @Override + public void encodeType(EncodingContext context, UaEncoder encoder, + ReferenceListEntryDataType value) { + encoder.encodeNodeId("ReferenceType", value.getReferenceType()); + encoder.encodeBoolean("IsForward", value.getIsForward()); + encoder.encodeExpandedNodeId("TargetNode", value.getTargetNode()); + } + } +} diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/TransactionErrorType.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/TransactionErrorType.java new file mode 100644 index 000000000..e471bab89 --- /dev/null +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/TransactionErrorType.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.core.types.structured; + +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import org.eclipse.milo.opcua.stack.core.NamespaceTable; +import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; +import org.eclipse.milo.opcua.stack.core.encoding.GenericDataTypeCodec; +import org.eclipse.milo.opcua.stack.core.encoding.UaDecoder; +import org.eclipse.milo.opcua.stack.core.encoding.UaEncoder; +import org.eclipse.milo.opcua.stack.core.types.UaStructuredType; +import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.StructureType; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.10.12 + */ +@EqualsAndHashCode( + callSuper = false +) +@SuperBuilder +@ToString +public class TransactionErrorType extends Structure implements UaStructuredType { + public static final ExpandedNodeId TYPE_ID = ExpandedNodeId.parse("ns=0;i=32285"); + + public static final ExpandedNodeId BINARY_ENCODING_ID = ExpandedNodeId.parse("i=32382"); + + public static final ExpandedNodeId XML_ENCODING_ID = ExpandedNodeId.parse("i=32386"); + + public static final ExpandedNodeId JSON_ENCODING_ID = ExpandedNodeId.parse("i=32390"); + + private final NodeId targetId; + + private final StatusCode error; + + private final LocalizedText message; + + public TransactionErrorType(NodeId targetId, StatusCode error, LocalizedText message) { + this.targetId = targetId; + this.error = error; + this.message = message; + } + + @Override + public ExpandedNodeId getTypeId() { + return TYPE_ID; + } + + @Override + public ExpandedNodeId getBinaryEncodingId() { + return BINARY_ENCODING_ID; + } + + @Override + public ExpandedNodeId getXmlEncodingId() { + return XML_ENCODING_ID; + } + + @Override + public ExpandedNodeId getJsonEncodingId() { + return JSON_ENCODING_ID; + } + + public NodeId getTargetId() { + return targetId; + } + + public StatusCode getError() { + return error; + } + + public LocalizedText getMessage() { + return message; + } + + public static StructureDefinition definition(NamespaceTable namespaceTable) { + return new StructureDefinition( + new NodeId(0, 32382), + new NodeId(0, 22), + StructureType.Structure, + new StructureField[]{ + new StructureField("TargetId", LocalizedText.NULL_VALUE, new NodeId(0, 17), -1, null, UInteger.valueOf(0), false), + new StructureField("Error", LocalizedText.NULL_VALUE, new NodeId(0, 19), -1, null, UInteger.valueOf(0), false), + new StructureField("Message", LocalizedText.NULL_VALUE, new NodeId(0, 21), -1, null, UInteger.valueOf(0), false) + } + ); + } + + public static final class Codec extends GenericDataTypeCodec { + @Override + public Class getType() { + return TransactionErrorType.class; + } + + @Override + public TransactionErrorType decodeType(EncodingContext context, UaDecoder decoder) { + NodeId targetId = decoder.decodeNodeId("TargetId"); + StatusCode error = decoder.decodeStatusCode("Error"); + LocalizedText message = decoder.decodeLocalizedText("Message"); + return new TransactionErrorType(targetId, error, message); + } + + @Override + public void encodeType(EncodingContext context, UaEncoder encoder, TransactionErrorType value) { + encoder.encodeNodeId("TargetId", value.getTargetId()); + encoder.encodeStatusCode("Error", value.getError()); + encoder.encodeLocalizedText("Message", value.getMessage()); + } + } +} diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/TrustListValidationOptions.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/TrustListValidationOptions.java new file mode 100644 index 000000000..36253221e --- /dev/null +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/TrustListValidationOptions.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.core.types.structured; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; + +/** + * @see https://reference.opcfoundation.org/v105/Core/docs/Part12/7.8.2/#7.8.2.8 + */ +@EqualsAndHashCode( + callSuper = true +) +@ToString +public class TrustListValidationOptions extends OptionSetUI32 { + public TrustListValidationOptions(UInteger value) { + super(value); + } + + public boolean getSuppressCertificateExpired() { + return get(Field.SuppressCertificateExpired); + } + + public boolean getSuppressHostNameInvalid() { + return get(Field.SuppressHostNameInvalid); + } + + public boolean getSuppressRevocationStatusUnknown() { + return get(Field.SuppressRevocationStatusUnknown); + } + + public boolean getSuppressIssuerCertificateExpired() { + return get(Field.SuppressIssuerCertificateExpired); + } + + public boolean getSuppressIssuerRevocationStatusUnknown() { + return get(Field.SuppressIssuerRevocationStatusUnknown); + } + + public boolean getCheckRevocationStatusOnline() { + return get(Field.CheckRevocationStatusOnline); + } + + public boolean getCheckRevocationStatusOffline() { + return get(Field.CheckRevocationStatusOffline); + } + + @Override + public UInteger getValue() { + return (UInteger) value; + } + + @Override + public Set toSet() { + return Arrays.stream(Field.values()) + .filter(this::get) + .collect(Collectors.toSet()); + } + + public static TrustListValidationOptions of(TrustListValidationOptions.Field... fields) { + long bits = 0L; + + for (Field f : fields) { + bits |= (1L << f.bitIndex); + } + + return new TrustListValidationOptions(UInteger.valueOf(bits)); + } + + public enum Field implements OptionSetUInteger.BitIndex { + SuppressCertificateExpired(0), + + SuppressHostNameInvalid(1), + + SuppressRevocationStatusUnknown(2), + + SuppressIssuerCertificateExpired(3), + + SuppressIssuerRevocationStatusUnknown(4), + + CheckRevocationStatusOnline(5), + + CheckRevocationStatusOffline(6); + + private final int bitIndex; + + Field(int bitIndex) { + this.bitIndex = bitIndex; + } + + @Override + public int getBitIndex() { + return bitIndex; + } + } +} diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UadpDataSetMessageContentMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UadpDataSetMessageContentMask.java index f2edef120..f4f833d3c 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UadpDataSetMessageContentMask.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UadpDataSetMessageContentMask.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -61,13 +62,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static UadpDataSetMessageContentMask of(Field... fields) { + public static UadpDataSetMessageContentMask of(UadpDataSetMessageContentMask.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -77,7 +78,7 @@ public static UadpDataSetMessageContentMask of(Field... fields) { return new UadpDataSetMessageContentMask(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { Timestamp(0), PicoSeconds(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UadpNetworkMessageContentMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UadpNetworkMessageContentMask.java index e887b3211..795a90b1f 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UadpNetworkMessageContentMask.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UadpNetworkMessageContentMask.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -81,13 +82,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static UadpNetworkMessageContentMask of(Field... fields) { + public static UadpNetworkMessageContentMask of(UadpNetworkMessageContentMask.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -97,7 +98,7 @@ public static UadpNetworkMessageContentMask of(Field... fields) { return new UadpNetworkMessageContentMask(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { PublisherId(0), GroupHeader(1), diff --git a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UserConfigurationMask.java b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UserConfigurationMask.java index f81196672..0593fe12b 100644 --- a/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UserConfigurationMask.java +++ b/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/types/structured/UserConfigurationMask.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUI32; +import org.eclipse.milo.opcua.stack.core.types.builtin.OptionSetUInteger; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; /** @@ -53,13 +54,13 @@ public UInteger getValue() { } @Override - public Set toSet() { + public Set toSet() { return Arrays.stream(Field.values()) .filter(this::get) .collect(Collectors.toSet()); } - public static UserConfigurationMask of(Field... fields) { + public static UserConfigurationMask of(UserConfigurationMask.Field... fields) { long bits = 0L; for (Field f : fields) { @@ -69,7 +70,7 @@ public static UserConfigurationMask of(Field... fields) { return new UserConfigurationMask(UInteger.valueOf(bits)); } - public enum Field implements BitIndex { + public enum Field implements OptionSetUInteger.BitIndex { NoDelete(0), Disabled(1), diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/UaStackServer.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/UaStackServer.java deleted file mode 100644 index 0868dd729..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/UaStackServer.java +++ /dev/null @@ -1,729 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server; - -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.LongAdder; -import java.util.stream.Collectors; - -import com.google.common.collect.ForwardingTable; -import com.google.common.collect.HashBasedTable; -import com.google.common.collect.Table; -import com.google.common.collect.Tables; -import io.netty.channel.Channel; -import org.eclipse.milo.opcua.stack.core.NamespaceTable; -import org.eclipse.milo.opcua.stack.core.ServerTable; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; -import org.eclipse.milo.opcua.stack.core.encoding.DefaultEncodingManager; -import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; -import org.eclipse.milo.opcua.stack.core.encoding.EncodingManager; -import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; -import org.eclipse.milo.opcua.stack.core.types.DataTypeManager; -import org.eclipse.milo.opcua.stack.core.types.DefaultDataTypeManager; -import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; -import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; -import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; -import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; -import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; -import org.eclipse.milo.opcua.stack.core.types.structured.ActivateSessionRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.AddNodesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.AddReferencesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.BrowseNextRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.BrowseRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.CallRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.CancelRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.CloseSessionRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.CreateMonitoredItemsRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.CreateSubscriptionRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteMonitoredItemsRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteNodesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteReferencesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.DeleteSubscriptionsRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.FindServersOnNetworkRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.FindServersRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.FindServersResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryReadRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.HistoryUpdateRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.ModifyMonitoredItemsRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.ModifySubscriptionRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.PublishRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.QueryFirstRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.QueryNextRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.ReadRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServer2Request; -import org.eclipse.milo.opcua.stack.core.types.structured.RegisterServerRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.RepublishRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.SetMonitoringModeRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.SetPublishingModeRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.SetTriggeringRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.TransferSubscriptionsRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.TranslateBrowsePathsToNodeIdsRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; -import org.eclipse.milo.opcua.stack.core.types.structured.WriteRequest; -import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; -import org.eclipse.milo.opcua.stack.core.util.FutureUtils; -import org.eclipse.milo.opcua.stack.core.util.Lazy; -import org.eclipse.milo.opcua.stack.core.util.Unit; -import org.eclipse.milo.opcua.stack.server.services.AttributeHistoryServiceSet; -import org.eclipse.milo.opcua.stack.server.services.AttributeServiceSet; -import org.eclipse.milo.opcua.stack.server.services.DiscoveryServiceSet; -import org.eclipse.milo.opcua.stack.server.services.MethodServiceSet; -import org.eclipse.milo.opcua.stack.server.services.MonitoredItemServiceSet; -import org.eclipse.milo.opcua.stack.server.services.NodeManagementServiceSet; -import org.eclipse.milo.opcua.stack.server.services.QueryServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequestHandler; -import org.eclipse.milo.opcua.stack.server.services.SessionServiceSet; -import org.eclipse.milo.opcua.stack.server.services.SubscriptionServiceSet; -import org.eclipse.milo.opcua.stack.server.services.ViewServiceSet; -import org.eclipse.milo.opcua.stack.server.transport.ServerChannelManager; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static java.util.stream.Collectors.toList; -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ubyte; -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; - -public class UaStackServer { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final ServiceHandlerTable serviceHandlerTable = new ServiceHandlerTable(); - - private final LongAdder rejectedRequestCount = new LongAdder(); - private final LongAdder securityRejectedRequestCount = new LongAdder(); - - private final Lazy applicationDescription = new Lazy<>(); - - private final NamespaceTable namespaceTable = new NamespaceTable(); - private final ServerTable serverTable = new ServerTable(); - - private final DataTypeManager dataTypeManager = - DefaultDataTypeManager.createAndInitialize(namespaceTable); - - private final EncodingManager encodingManager = - DefaultEncodingManager.createAndInitialize(); - - private final AtomicLong channelIds = new AtomicLong(); - private final AtomicLong tokenIds = new AtomicLong(); - - private final List channels = new CopyOnWriteArrayList<>(); - - private final Set boundEndpoints = ConcurrentHashMap.newKeySet(); - - private final ServerChannelManager channelManager; - private final EncodingContext encodingContext; - - private final UaStackServerConfig config; - - public UaStackServer(UaStackServerConfig config) { - this.config = config; - - serverTable.add(config.getApplicationUri()); - - channelManager = new ServerChannelManager(this); - - encodingContext = new EncodingContext() { - @Override - public DataTypeManager getDataTypeManager() { - return dataTypeManager; - } - - @Override - public EncodingManager getEncodingManager() { - return encodingManager; - } - - @Override - public EncodingLimits getEncodingLimits() { - return config.getEncodingLimits(); - } - - @Override - public NamespaceTable getNamespaceTable() { - return namespaceTable; - } - - @Override - public ServerTable getServerTable() { - return serverTable; - } - }; - - config.getEndpoints().forEach(endpoint -> { - String path = EndpointUtil.getPath(endpoint.getEndpointUrl()); - - addServiceSet(path, new DefaultDiscoveryServiceSet(UaStackServer.this)); - }); - } - - public UaStackServerConfig getConfig() { - return config; - } - - public CompletableFuture startup() { - List> futures = new ArrayList<>(); - - config.getEndpoints() - .stream() - .sorted(Comparator.comparing(EndpointConfiguration::getTransportProfile)) - .forEach(endpoint -> { - logger.info( - "Binding endpoint {} to {}:{} [{}/{}]", - endpoint.getEndpointUrl(), - endpoint.getBindAddress(), - endpoint.getBindPort(), - endpoint.getSecurityPolicy(), - endpoint.getSecurityMode()); - - futures.add( - channelManager.bind(endpoint) - .whenComplete((u, ex) -> { - if (u != null) { - boundEndpoints.add(endpoint); - } - }) - .exceptionally(ex -> { - logger.warn( - "Bind failed for endpoint {}", - endpoint.getEndpointUrl(), ex); - - return Unit.VALUE; - }) - ); - }); - - return FutureUtils.sequence(futures) - .thenApply(u -> UaStackServer.this); - } - - public CompletableFuture shutdown() { - List> futures = new ArrayList<>(); - - config.getEndpoints().forEach(endpoint -> - futures.add( - channelManager.unbind(endpoint).exceptionally(ex -> { - logger.warn( - "Unbind failed for endpoint {}", - endpoint.getEndpointUrl(), ex); - - return Unit.VALUE; - }) - ) - ); - - channels.forEach(channel -> { - CompletableFuture f = new CompletableFuture<>(); - - channel.close().addListener(fv -> f.complete(Unit.VALUE)); - - futures.add(f); - }); - - channels.clear(); - - boundEndpoints.clear(); - - return FutureUtils.sequence(futures) - .thenApply(u -> UaStackServer.this); - } - - public NamespaceTable getNamespaceTable() { - return namespaceTable; - } - - public ServerTable getServerTable() { - return serverTable; - } - - public DataTypeManager getDataTypeManager() { - return dataTypeManager; - } - - public EncodingManager getEncodingManager() { - return encodingManager; - } - - public EncodingContext getEncodingContext() { - return encodingContext; - } - - public void registerConnectedChannel(Channel channel) { - channels.add(channel); - } - - public void unregisterConnectedChannel(Channel channel) { - channels.remove(channel); - } - - public List getConnectedChannels() { - return channels; - } - - /** - * Get the {@link EndpointConfiguration}s that were successfully bound during startup. - * - * @return the {@link EndpointConfiguration}s that were successfully bound during startup. - */ - public Set getBoundEndpoints() { - return boundEndpoints; - } - - public void onServiceRequest(String path, ServiceRequest serviceRequest) { - config.getExecutor().execute(() -> handleServiceRequest(path, serviceRequest)); - } - - private void handleServiceRequest(String path, ServiceRequest serviceRequest) { - UaRequestMessageType request = serviceRequest.getRequest(); - - if (logger.isTraceEnabled()) { - logger.trace( - "ServiceRequest received path={}, requestHandle={} request={}", - path, - request.getRequestHeader().getRequestHandle(), - request.getClass().getSimpleName() - ); - - serviceRequest.getFuture().whenComplete((response, ex) -> { - if (response != null) { - logger.trace( - "ServiceRequest completed path={}, requestHandle={} response={}", - path, - response.getResponseHeader().getRequestHandle(), - response.getClass().getSimpleName() - ); - } else { - logger.trace( - "ServiceRequest completed exceptionally path={}, requestHandle={}", - path, - request.getRequestHeader().getRequestHandle(), - ex - ); - } - }); - } - - ServiceRequestHandler serviceHandler = getServiceHandler(path, request.getTypeId()); - - try { - if (serviceHandler != null) { - serviceHandler.handle(serviceRequest); - } else { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - } catch (UaException e) { - serviceRequest.setServiceFault(e); - } catch (Throwable t) { - logger.error("Uncaught Throwable executing handler: {}", serviceHandler, t); - serviceRequest.setServiceFault(StatusCodes.Bad_InternalError); - } - } - - public long getNextChannelId() { - return channelIds.incrementAndGet(); - } - - public long getNextTokenId() { - return tokenIds.incrementAndGet(); - } - - private ApplicationDescription getApplicationDescription() { - return applicationDescription.getOrCompute(() -> { - List discoveryUrls = config.getEndpoints() - .stream() - .map(EndpointConfiguration::getEndpointUrl) - .filter(url -> url.endsWith("/discovery")) - .distinct() - .collect(toList()); - - if (discoveryUrls.isEmpty()) { - discoveryUrls = config.getEndpoints() - .stream() - .map(EndpointConfiguration::getEndpointUrl) - .distinct() - .collect(toList()); - } - - return new ApplicationDescription( - config.getApplicationUri(), - config.getProductUri(), - config.getApplicationName(), - ApplicationType.Server, - null, - null, - a(discoveryUrls, String.class) - ); - }); - } - - public List getEndpointDescriptions() { - return config.getEndpoints() - .stream() - .map(this::transformEndpoint) - .collect(Collectors.toUnmodifiableList()); - } - - private EndpointDescription transformEndpoint(EndpointConfiguration endpoint) { - return new EndpointDescription( - endpoint.getEndpointUrl(), - getApplicationDescription(), - certificateByteString(endpoint.getCertificate()), - endpoint.getSecurityMode(), - endpoint.getSecurityPolicy().getUri(), - a(endpoint.getTokenPolicies(), UserTokenPolicy.class), - endpoint.getTransportProfile().getUri(), - ubyte(getSecurityLevel(endpoint.getSecurityPolicy(), endpoint.getSecurityMode())) - ); - } - - private ByteString certificateByteString(@Nullable X509Certificate certificate) { - if (certificate != null) { - try { - return ByteString.of(certificate.getEncoded()); - } catch (CertificateEncodingException e) { - logger.error("Error decoding certificate.", e); - return ByteString.NULL_VALUE; - } - } else { - return ByteString.NULL_VALUE; - } - } - - private static short getSecurityLevel(SecurityPolicy securityPolicy, MessageSecurityMode securityMode) { - short securityLevel = 0; - - switch (securityPolicy) { - case Aes256_Sha256_RsaPss: - case Basic256Sha256: - securityLevel |= 0x08; - break; - case Aes128_Sha256_RsaOaep: - securityLevel |= 0x04; - break; - case Basic256: - case Basic128Rsa15: - securityLevel |= 0x01; - break; - case None: - default: - break; - } - - switch (securityMode) { - case SignAndEncrypt: - securityLevel |= 0x80; - break; - case Sign: - securityLevel |= 0x40; - break; - default: - securityLevel |= 0x20; - break; - } - - return securityLevel; - } - - public LongAdder getRejectedRequestCount() { - return rejectedRequestCount; - } - - public LongAdder getSecurityRejectedRequestCount() { - return securityRejectedRequestCount; - } - - public void addServiceHandler( - String path, - ExpandedNodeId dataTypeId, - ServiceRequestHandler serviceHandler) { - - logger.debug("Adding ServiceHandler for {} at {}", dataTypeId, path); - - serviceHandlerTable.put(path, dataTypeId, serviceHandler); - } - - public void removeServiceHandler(String path, ExpandedNodeId dataTypeId) { - logger.debug("Removing ServiceHandler for {} at {}", dataTypeId, path); - - serviceHandlerTable.remove(path, dataTypeId); - } - - @Nullable - public ServiceRequestHandler getServiceHandler(String path, ExpandedNodeId dataTypeId) { - return serviceHandlerTable.get(path, dataTypeId); - } - - public void addServiceSet(String path, AttributeServiceSet serviceSet) { - addServiceHandler(path, ReadRequest.TYPE_ID, serviceSet::onRead); - addServiceHandler(path, WriteRequest.TYPE_ID, serviceSet::onWrite); - } - - public void addServiceSet(String path, AttributeHistoryServiceSet serviceSet) { - addServiceHandler(path, HistoryReadRequest.TYPE_ID, serviceSet::onHistoryRead); - addServiceHandler(path, HistoryUpdateRequest.TYPE_ID, serviceSet::onHistoryUpdate); - } - - public void addServiceSet(String path, DiscoveryServiceSet serviceSet) { - addServiceHandler(path, GetEndpointsRequest.TYPE_ID, serviceSet::onGetEndpoints); - addServiceHandler(path, FindServersRequest.TYPE_ID, serviceSet::onFindServers); - addServiceHandler(path, FindServersOnNetworkRequest.TYPE_ID, serviceSet::onFindServersOnNetwork); - addServiceHandler(path, RegisterServerRequest.TYPE_ID, serviceSet::onRegisterServer); - addServiceHandler(path, RegisterServer2Request.TYPE_ID, serviceSet::onRegisterServer2); - } - - public void addServiceSet(String path, QueryServiceSet serviceSet) { - addServiceHandler(path, QueryFirstRequest.TYPE_ID, serviceSet::onQueryFirst); - addServiceHandler(path, QueryNextRequest.TYPE_ID, serviceSet::onQueryNext); - } - - public void addServiceSet(String path, MethodServiceSet serviceSet) { - addServiceHandler(path, CallRequest.TYPE_ID, serviceSet::onCall); - } - - public void addServiceSet(String path, MonitoredItemServiceSet serviceSet) { - addServiceHandler(path, CreateMonitoredItemsRequest.TYPE_ID, serviceSet::onCreateMonitoredItems); - addServiceHandler(path, ModifyMonitoredItemsRequest.TYPE_ID, serviceSet::onModifyMonitoredItems); - addServiceHandler(path, DeleteMonitoredItemsRequest.TYPE_ID, serviceSet::onDeleteMonitoredItems); - addServiceHandler(path, SetMonitoringModeRequest.TYPE_ID, serviceSet::onSetMonitoringMode); - addServiceHandler(path, SetTriggeringRequest.TYPE_ID, serviceSet::onSetTriggering); - } - - public void addServiceSet(String path, NodeManagementServiceSet serviceSet) { - addServiceHandler(path, AddNodesRequest.TYPE_ID, serviceSet::onAddNodes); - addServiceHandler(path, DeleteNodesRequest.TYPE_ID, serviceSet::onDeleteNodes); - addServiceHandler(path, AddReferencesRequest.TYPE_ID, serviceSet::onAddReferences); - addServiceHandler(path, DeleteReferencesRequest.TYPE_ID, serviceSet::onDeleteReferences); - } - - public void addServiceSet(String path, SessionServiceSet serviceSet) { - addServiceHandler(path, CreateSessionRequest.TYPE_ID, serviceSet::onCreateSession); - addServiceHandler(path, ActivateSessionRequest.TYPE_ID, serviceSet::onActivateSession); - addServiceHandler(path, CloseSessionRequest.TYPE_ID, serviceSet::onCloseSession); - addServiceHandler(path, CancelRequest.TYPE_ID, serviceSet::onCancel); - } - - public void addServiceSet(String path, SubscriptionServiceSet serviceSet) { - addServiceHandler(path, CreateSubscriptionRequest.TYPE_ID, serviceSet::onCreateSubscription); - addServiceHandler(path, ModifySubscriptionRequest.TYPE_ID, serviceSet::onModifySubscription); - addServiceHandler(path, DeleteSubscriptionsRequest.TYPE_ID, serviceSet::onDeleteSubscriptions); - addServiceHandler(path, TransferSubscriptionsRequest.TYPE_ID, serviceSet::onTransferSubscriptions); - addServiceHandler(path, SetPublishingModeRequest.TYPE_ID, serviceSet::onSetPublishingMode); - addServiceHandler(path, PublishRequest.TYPE_ID, serviceSet::onPublish); - addServiceHandler(path, RepublishRequest.TYPE_ID, serviceSet::onRepublish); - } - - public void addServiceSet(String path, ViewServiceSet serviceSet) { - addServiceHandler(path, BrowseRequest.TYPE_ID, serviceSet::onBrowse); - addServiceHandler(path, BrowseNextRequest.TYPE_ID, serviceSet::onBrowseNext); - addServiceHandler(path, TranslateBrowsePathsToNodeIdsRequest.TYPE_ID, serviceSet::onTranslateBrowsePaths); - addServiceHandler(path, RegisterNodesRequest.TYPE_ID, serviceSet::onRegisterNodes); - addServiceHandler(path, UnregisterNodesRequest.TYPE_ID, serviceSet::onUnregisterNodes); - } - - private static class DefaultDiscoveryServiceSet implements DiscoveryServiceSet { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final UaStackServerConfig config; - - private final UaStackServer stackServer; - - public DefaultDiscoveryServiceSet(UaStackServer stackServer) { - this.stackServer = stackServer; - - this.config = stackServer.getConfig(); - } - - @Override - public void onGetEndpoints(ServiceRequest serviceRequest) { - GetEndpointsRequest request = (GetEndpointsRequest) serviceRequest.getRequest(); - - List profileUris = request.getProfileUris() != null ? - List.of(request.getProfileUris()) : - Collections.emptyList(); - - List allEndpoints = stackServer.getEndpointDescriptions() - .stream() - .filter(ed -> !ed.getEndpointUrl().endsWith("/discovery")) - .filter(ed -> filterProfileUris(ed, profileUris)) - .distinct() - .collect(Collectors.toList()); - - ApplicationDescription filteredApplicationDescription = - getFilteredApplicationDescription(request.getEndpointUrl()); - - List matchingEndpoints = allEndpoints.stream() - .filter(endpoint -> filterEndpointUrls(endpoint, request.getEndpointUrl())) - .map(endpoint -> - replaceApplicationDescription( - endpoint, - filteredApplicationDescription - ) - ) - .distinct() - .collect(toList()); - - GetEndpointsResponse response = new GetEndpointsResponse( - serviceRequest.createResponseHeader(), - matchingEndpoints.isEmpty() ? - allEndpoints.toArray(new EndpointDescription[0]) : - matchingEndpoints.toArray(new EndpointDescription[0]) - ); - - serviceRequest.setResponse(response); - } - - private boolean filterProfileUris(EndpointDescription endpoint, List profileUris) { - return profileUris.size() == 0 || profileUris.contains(endpoint.getTransportProfileUri()); - } - - private boolean filterEndpointUrls(EndpointDescription endpoint, String endpointUrl) { - try { - String requestedHost = EndpointUtil.getHost(endpointUrl); - String endpointHost = EndpointUtil.getHost(endpoint.getEndpointUrl()); - - return Objects.requireNonNullElse(requestedHost, "").equalsIgnoreCase(endpointHost); - } catch (Throwable e) { - logger.debug("Unable to create URI.", e); - return false; - } - } - - private EndpointDescription replaceApplicationDescription( - EndpointDescription endpoint, - ApplicationDescription applicationDescription) { - - return new EndpointDescription( - endpoint.getEndpointUrl(), - applicationDescription, - endpoint.getServerCertificate(), - endpoint.getSecurityMode(), - endpoint.getSecurityPolicyUri(), - endpoint.getUserIdentityTokens(), - endpoint.getTransportProfileUri(), - endpoint.getSecurityLevel() - ); - } - - @Override - public void onFindServers(ServiceRequest serviceRequest) { - FindServersRequest request = (FindServersRequest) serviceRequest.getRequest(); - - List serverUris = request.getServerUris() != null ? - List.of(request.getServerUris()) : - Collections.emptyList(); - - List applicationDescriptions = - List.of(getFilteredApplicationDescription(request.getEndpointUrl())); - - applicationDescriptions = applicationDescriptions.stream() - .filter(ad -> filterServerUris(ad, serverUris)) - .collect(toList()); - - FindServersResponse response = new FindServersResponse( - serviceRequest.createResponseHeader(), - a(applicationDescriptions, ApplicationDescription.class) - ); - - serviceRequest.setResponse(response); - } - - private ApplicationDescription getFilteredApplicationDescription(String endpointUrl) { - List allDiscoveryUrls = config.getEndpoints() - .stream() - .map(EndpointConfiguration::getEndpointUrl) - .filter(url -> url.endsWith("/discovery")) - .distinct() - .collect(toList()); - - if (allDiscoveryUrls.isEmpty()) { - allDiscoveryUrls = config.getEndpoints() - .stream() - .map(EndpointConfiguration::getEndpointUrl) - .distinct() - .collect(toList()); - } - - List matchingDiscoveryUrls = allDiscoveryUrls.stream() - .filter(discoveryUrl -> { - try { - - String requestedHost = EndpointUtil.getHost(endpointUrl); - String discoveryHost = EndpointUtil.getHost(discoveryUrl); - - logger.debug("requestedHost={}, discoveryHost={}", requestedHost, discoveryHost); - - return Objects.requireNonNullElse(requestedHost, "").equalsIgnoreCase(discoveryHost); - } catch (Throwable e) { - logger.debug("Unable to create URI.", e); - return false; - } - }) - .distinct() - .collect(toList()); - - - logger.debug("Matching discovery URLs: {}", matchingDiscoveryUrls); - - return new ApplicationDescription( - config.getApplicationUri(), - config.getProductUri(), - config.getApplicationName(), - ApplicationType.Server, - null, - null, - matchingDiscoveryUrls.isEmpty() ? - allDiscoveryUrls.toArray(new String[0]) : - matchingDiscoveryUrls.toArray(new String[0]) - ); - } - - private boolean filterServerUris(ApplicationDescription ad, List serverUris) { - return serverUris.size() == 0 || serverUris.contains(ad.getApplicationUri()); - } - - } - - private static class ServiceHandlerTable extends - ForwardingTable { - - private final Table delegate = - Tables.synchronizedTable(HashBasedTable.create()); - - @Override - protected Table delegate() { - return delegate; - } - - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/UaStackServerConfig.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/UaStackServerConfig.java deleted file mode 100644 index 20829ecf6..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/UaStackServerConfig.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server; - -import java.security.KeyPair; -import java.security.cert.X509Certificate; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.function.Consumer; - -import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; -import org.eclipse.milo.opcua.stack.core.security.CertificateManager; -import org.eclipse.milo.opcua.stack.core.security.TrustListManager; -import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; -import org.eclipse.milo.opcua.stack.server.security.ServerCertificateValidator; - -public interface UaStackServerConfig { - - /** - * @return the {@link EndpointConfiguration}s for this server. - */ - Set getEndpoints(); - - /** - * Get the application name for the server. - *

- * This will be used in the {@link ApplicationDescription} returned to clients. - * - * @return the application name for the server. - */ - LocalizedText getApplicationName(); - - /** - * Get the application uri for the server. - *

- * This will be used in the {@link ApplicationDescription} returned to clients. - *

- * The application uri must match the application uri used on the server's application instance certificate. - * - * @return the application uri for the server. - */ - String getApplicationUri(); - - /** - * Get the product uri for the server. - *

- * This will be used in the {@link ApplicationDescription} returned to clients. - * - * @return the product uri for the server. - */ - String getProductUri(); - - /** - * @return the configured {@link EncodingLimits}. - */ - EncodingLimits getEncodingLimits(); - - /** - * @return the minimum allowable secure channel lifetime, in milliseconds. - */ - UInteger getMinimumSecureChannelLifetime(); - - /** - * @return the maximum allowable secure channel lifetime, in milliseconds. - */ - UInteger getMaximumSecureChannelLifetime(); - - /** - * @return the {@link CertificateManager} for this server. - */ - CertificateManager getCertificateManager(); - - /** - * @return the {@link TrustListManager} for this server. - */ - TrustListManager getTrustListManager(); - - /** - * @return the {@link ServerCertificateValidator} for this server. - */ - ServerCertificateValidator getCertificateValidator(); - - /** - * @return the {@link KeyPair} used for SSL/TLS with HTTPS endpoints. - */ - Optional getHttpsKeyPair(); - - /** - * @return the {@link X509Certificate} used for SSL/TLS with HTTPS endpoints. - * @deprecated This will only return the leaf certificate, use @{{@link #getHttpsCertificateChain()}} to get the - * full chain. - */ - @Deprecated - default Optional getHttpsCertificate() { - return getHttpsCertificateChain().flatMap(chain -> Optional.ofNullable(chain[0])); - } - - /** - * @return the {@link X509Certificate} used for SSL/TLS with HTTPS endpoints. - */ - Optional getHttpsCertificateChain(); - - /** - * @return the {@link ExecutorService} for this server. - */ - ExecutorService getExecutor(); - - /** - * @return a new {@link UaStackServerConfigBuilder}. - */ - static UaStackServerConfigBuilder builder() { - return new UaStackServerConfigBuilder(); - } - - /** - * Copy the values from an existing {@link UaStackServerConfig} into a new {@link UaStackServerConfigBuilder}. - *

- * This builder can be used to make any desired modifications before invoking - * {@link UaStackServerConfigBuilder#build()} to produce a new config. - * - * @param config the {@link UaStackServerConfig} to copy from. - * @return a {@link UaStackServerConfigBuilder} pre-populated with values from {@code config}. - */ - static UaStackServerConfigBuilder copy(UaStackServerConfig config) { - UaStackServerConfigBuilder builder = builder(); - - builder.setEndpoints(config.getEndpoints()); - builder.setApplicationName(config.getApplicationName()); - builder.setApplicationUri(config.getApplicationUri()); - builder.setProductUri(config.getProductUri()); - builder.setEncodingLimits(config.getEncodingLimits()); - builder.setMinimumSecureChannelLifetime(config.getMinimumSecureChannelLifetime()); - builder.setMaximumSecureChannelLifetime(config.getMaximumSecureChannelLifetime()); - builder.setCertificateManager(config.getCertificateManager()); - builder.setTrustListManager(config.getTrustListManager()); - builder.setCertificateValidator(config.getCertificateValidator()); - builder.setHttpsKeyPair(config.getHttpsKeyPair().orElse(null)); - builder.setHttpsCertificateChain(config.getHttpsCertificateChain().orElse(null)); - builder.setExecutor(config.getExecutor()); - - return builder; - } - - /** - * Copy the values from an existing {@link UaStackServerConfig} into a new {@link UaStackServerConfigBuilder} - * and then submit the builder to the provided consumer for modification. - * - * @param config the {@link UaStackServerConfig} to copy from. - * @param consumer a {@link Consumer} that may modify the builder. - * @return a {@link UaStackServerConfig} built from the builder provided to {@code consumer}. - */ - static UaStackServerConfig copy( - UaStackServerConfig config, - Consumer consumer) { - - UaStackServerConfigBuilder builder = copy(config); - - consumer.accept(builder); - - return builder.build(); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/UaStackServerConfigBuilder.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/UaStackServerConfigBuilder.java deleted file mode 100644 index cd4f911e3..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/UaStackServerConfigBuilder.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server; - -import java.security.KeyPair; -import java.security.cert.X509Certificate; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ExecutorService; - -import org.eclipse.milo.opcua.stack.core.Stack; -import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; -import org.eclipse.milo.opcua.stack.core.security.CertificateManager; -import org.eclipse.milo.opcua.stack.core.security.TrustListManager; -import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.server.security.ServerCertificateValidator; -import org.jetbrains.annotations.Nullable; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - -public class UaStackServerConfigBuilder { - - private Set endpoints = new HashSet<>(); - - private LocalizedText applicationName = LocalizedText - .english("server application name not configured"); - - private String applicationUri = "server application uri not configured"; - - private String productUri = "server product uri not configured"; - - private EncodingLimits encodingLimits = EncodingLimits.DEFAULT; - - private UInteger minimumSecureChannelLifetime = uint(60_000); - private UInteger maximumSecureChannelLifetime = uint(60_000 * 60 * 24); - - private CertificateManager certificateManager; - private TrustListManager trustListManager; - private ServerCertificateValidator certificateValidator; - - private KeyPair httpsKeyPair; - private X509Certificate[] httpsCertificate; - - private ExecutorService executor; - - public UaStackServerConfigBuilder setEndpoints(Set endpointConfigurations) { - this.endpoints = endpointConfigurations; - return this; - } - - public UaStackServerConfigBuilder setApplicationName(LocalizedText applicationName) { - this.applicationName = applicationName; - return this; - } - - public UaStackServerConfigBuilder setApplicationUri(String applicationUri) { - this.applicationUri = applicationUri; - return this; - } - - public UaStackServerConfigBuilder setProductUri(String productUri) { - this.productUri = productUri; - return this; - } - - public UaStackServerConfigBuilder setEncodingLimits(EncodingLimits encodingLimits) { - this.encodingLimits = encodingLimits; - return this; - } - - public UaStackServerConfigBuilder setMinimumSecureChannelLifetime(UInteger minimumSecureChannelLifetime) { - this.minimumSecureChannelLifetime = minimumSecureChannelLifetime; - return this; - } - - public UaStackServerConfigBuilder setMaximumSecureChannelLifetime(UInteger maximumSecureChannelLifetime) { - this.maximumSecureChannelLifetime = maximumSecureChannelLifetime; - return this; - } - - public UaStackServerConfigBuilder setCertificateManager(CertificateManager certificateManager) { - this.certificateManager = certificateManager; - return this; - } - - public UaStackServerConfigBuilder setTrustListManager(TrustListManager trustListManager) { - this.trustListManager = trustListManager; - return this; - } - - public UaStackServerConfigBuilder setCertificateValidator(ServerCertificateValidator certificateValidator) { - this.certificateValidator = certificateValidator; - return this; - } - - public UaStackServerConfigBuilder setHttpsKeyPair(KeyPair httpsKeyPair) { - this.httpsKeyPair = httpsKeyPair; - return this; - } - - public UaStackServerConfigBuilder setHttpsCertificateChain(X509Certificate[] httpsCertificate) { - this.httpsCertificate = httpsCertificate; - return this; - } - - @Deprecated - public UaStackServerConfigBuilder setHttpsCertificate(X509Certificate httpsCertificate) { - this.httpsCertificate = new X509Certificate[] { httpsCertificate }; - return this; - } - - public UaStackServerConfigBuilder setExecutor(ExecutorService executor) { - this.executor = executor; - return this; - } - - public UaStackServerConfig build() { - if (executor == null) { - executor = Stack.sharedExecutor(); - } - - return new UaStackServerConfigImpl( - endpoints, - applicationName, - applicationUri, - productUri, - encodingLimits, - minimumSecureChannelLifetime, - maximumSecureChannelLifetime, - certificateManager, - trustListManager, - certificateValidator, - httpsKeyPair, - httpsCertificate, - executor - ); - } - - - private static class UaStackServerConfigImpl implements UaStackServerConfig { - - private final Set endpointConfigurations; - - private final LocalizedText applicationName; - private final String applicationUri; - private final String productUri; - - private final EncodingLimits encodingLimits; - - private final UInteger minimumSecureChannelLifetime; - private final UInteger maximumSecureChannelLifetime; - - private final CertificateManager certificateManager; - private final ServerCertificateValidator certificateValidator; - private final TrustListManager trustListManager; - - private final KeyPair httpsKeyPair; - private final X509Certificate[] httpsCertificate; - - private final ExecutorService executor; - - UaStackServerConfigImpl( - Set endpointConfigurations, - LocalizedText applicationName, - String applicationUri, - String productUri, - EncodingLimits encodingLimits, - UInteger minimumSecureChannelLifetime, - UInteger maximumSecureChannelLifetime, - CertificateManager certificateManager, - TrustListManager trustListManager, - ServerCertificateValidator certificateValidator, - @Nullable KeyPair httpsKeyPair, - @Nullable X509Certificate[] httpsCertificate, - ExecutorService executor - ) { - - this.endpointConfigurations = endpointConfigurations; - this.applicationName = applicationName; - this.applicationUri = applicationUri; - this.productUri = productUri; - this.encodingLimits = encodingLimits; - this.minimumSecureChannelLifetime = minimumSecureChannelLifetime; - this.maximumSecureChannelLifetime = maximumSecureChannelLifetime; - this.trustListManager = trustListManager; - this.certificateManager = certificateManager; - this.certificateValidator = certificateValidator; - this.httpsKeyPair = httpsKeyPair; - this.httpsCertificate = httpsCertificate; - this.executor = executor; - } - - @Override - public Set getEndpoints() { - return endpointConfigurations; - } - - @Override - public LocalizedText getApplicationName() { - return applicationName; - } - - @Override - public String getApplicationUri() { - return applicationUri; - } - - @Override - public String getProductUri() { - return productUri; - } - - @Override - public EncodingLimits getEncodingLimits() { - return encodingLimits; - } - - @Override - public UInteger getMinimumSecureChannelLifetime() { - return minimumSecureChannelLifetime; - } - - @Override - public UInteger getMaximumSecureChannelLifetime() { - return maximumSecureChannelLifetime; - } - - @Override - public CertificateManager getCertificateManager() { - return certificateManager; - } - - @Override - public TrustListManager getTrustListManager() { - return trustListManager; - } - - @Override - public ServerCertificateValidator getCertificateValidator() { - return certificateValidator; - } - - @Override - public Optional getHttpsKeyPair() { - return Optional.ofNullable(httpsKeyPair); - } - - @Override - public Optional getHttpsCertificateChain() { - return Optional.ofNullable(httpsCertificate); - } - - @Override - public ExecutorService getExecutor() { - return executor; - } - - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/AttributeHistoryServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/AttributeHistoryServiceSet.java deleted file mode 100644 index d2ac709cf..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/AttributeHistoryServiceSet.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface AttributeHistoryServiceSet { - - default void onHistoryRead(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onHistoryUpdate(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/AttributeServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/AttributeServiceSet.java deleted file mode 100644 index cd702ae20..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/AttributeServiceSet.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface AttributeServiceSet { - - default void onRead(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onWrite(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/DiscoveryServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/DiscoveryServiceSet.java deleted file mode 100644 index 5e7482d2c..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/DiscoveryServiceSet.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface DiscoveryServiceSet { - - default void onFindServers(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onFindServersOnNetwork(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onGetEndpoints(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onRegisterServer(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onRegisterServer2(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/MethodServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/MethodServiceSet.java deleted file mode 100644 index 00a729c81..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/MethodServiceSet.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface MethodServiceSet { - - default void onCall(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/MonitoredItemServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/MonitoredItemServiceSet.java deleted file mode 100644 index 92b0b31b2..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/MonitoredItemServiceSet.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface MonitoredItemServiceSet { - - default void onCreateMonitoredItems(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onModifyMonitoredItems(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onDeleteMonitoredItems(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onSetMonitoringMode(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onSetTriggering(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/NodeManagementServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/NodeManagementServiceSet.java deleted file mode 100644 index f5aedabb3..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/NodeManagementServiceSet.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface NodeManagementServiceSet { - - default void onAddNodes(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onDeleteNodes(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onAddReferences(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onDeleteReferences(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/QueryServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/QueryServiceSet.java deleted file mode 100644 index 1f1978bde..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/QueryServiceSet.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface QueryServiceSet { - - default void onQueryFirst(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onQueryNext(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ServiceRequest.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ServiceRequest.java deleted file mode 100644 index e5e085052..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ServiceRequest.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import java.net.InetAddress; -import java.util.concurrent.CompletableFuture; - -import com.google.common.base.MoreObjects; -import io.netty.util.DefaultAttributeMap; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; -import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; -import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; -import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.jetbrains.annotations.Nullable; - -public class ServiceRequest extends DefaultAttributeMap { - - private final CompletableFuture future = new CompletableFuture<>(); - - private final long receivedAtNanos = System.nanoTime(); - - private final UaStackServer server; - private final UaRequestMessageType request; - private final EndpointDescription endpoint; - private final long secureChannelId; - private final InetAddress clientAddress; - private final ByteString clientCertificateBytes; - - public ServiceRequest( - UaStackServer server, - UaRequestMessageType request, - EndpointDescription endpoint, - long secureChannelId, - InetAddress clientAddress, - @Nullable ByteString clientCertificateBytes) { - - this.server = server; - this.request = request; - this.endpoint = endpoint; - this.secureChannelId = secureChannelId; - this.clientAddress = clientAddress; - this.clientCertificateBytes = clientCertificateBytes; - - future.whenComplete(this::updateDiagnosticCounters); - } - - public UaStackServer getServer() { - return server; - } - - public EndpointDescription getEndpoint() { - return endpoint; - } - - public InetAddress getClientAddress() { - return clientAddress; - } - - /** - * Get the client certificate bytes, or {@code null} if not available. - *

- * Only available on SecureConversation-based transports with security enabled. - * - * @return the client certificate bytes, or {@code null} if not available. - */ - @Nullable - public ByteString getClientCertificateBytes() { - return clientCertificateBytes; - } - - public long getSecureChannelId() { - return secureChannelId; - } - - public UaRequestMessageType getRequest() { - return request; - } - - public CompletableFuture getFuture() { - return future; - } - - public long getReceivedAtNanos() { - return receivedAtNanos; - } - - public void setResponse(UaResponseMessageType response) { - future.complete(response); - } - - public void setServiceFault(UaException exception) { - future.completeExceptionally(exception); - } - - public void setServiceFault(long statusCode) { - setServiceFault(new StatusCode(statusCode)); - } - - public void setServiceFault(StatusCode statusCode) { - future.completeExceptionally(new UaException(statusCode, "ServiceFault")); - } - - public ResponseHeader createResponseHeader() { - return createResponseHeader(StatusCode.GOOD); - } - - public ResponseHeader createResponseHeader(long statusCode) { - return createResponseHeader(new StatusCode(statusCode)); - } - - public ResponseHeader createResponseHeader(StatusCode serviceResult) { - return new ResponseHeader( - DateTime.now(), - request.getRequestHeader().getRequestHandle(), - serviceResult, - null, null, null - ); - } - - public ServiceFault createServiceFault(long statusCode) { - ResponseHeader responseHeader = new ResponseHeader( - DateTime.now(), - request.getRequestHeader().getRequestHandle(), - new StatusCode(statusCode), - null, null, null - ); - - return new ServiceFault(responseHeader); - } - - public ServiceFault createServiceFault(Throwable throwable) { - UaException exception = (throwable instanceof UaException) ? - (UaException) throwable : new UaException(throwable); - - ResponseHeader responseHeader = new ResponseHeader( - DateTime.now(), - request.getRequestHeader().getRequestHandle(), - exception.getStatusCode(), - null, null, null - ); - - return new ServiceFault(responseHeader); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("request", request.getClass().getSimpleName()) - .toString(); - } - - private void updateDiagnosticCounters( - @SuppressWarnings("unused") @Nullable UaResponseMessageType r, - @Nullable Throwable ex - ) { - - if (ex != null) { - StatusCode statusCode = UaException.extractStatusCode(ex) - .orElse(new StatusCode(StatusCodes.Bad_InternalError)); - - if (statusCode.isSecurityError()) { - server.getSecurityRejectedRequestCount().increment(); - } - - server.getRejectedRequestCount().increment(); - } - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ServiceRequestHandler.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ServiceRequestHandler.java deleted file mode 100644 index 793614f4a..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ServiceRequestHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface ServiceRequestHandler { - - void handle(ServiceRequest serviceRequest) throws UaException; - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ServiceResponse.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ServiceResponse.java deleted file mode 100644 index 3d04a5ed2..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ServiceResponse.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import com.google.common.base.MoreObjects; -import com.google.common.base.MoreObjects.ToStringHelper; -import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; -import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; - -public class ServiceResponse { - - private final UaRequestMessageType request; - private final UaResponseMessageType response; - private final long requestId; - private final boolean serviceFault; - - public ServiceResponse(UaRequestMessageType request, long requestId, UaResponseMessageType response) { - this.request = request; - this.requestId = requestId; - this.response = response; - this.serviceFault = false; - } - - public ServiceResponse(UaRequestMessageType request, long requestId, ServiceFault serviceFault) { - this.request = request; - this.requestId = requestId; - this.response = serviceFault; - this.serviceFault = true; - } - - public UaRequestMessageType getRequest() { - return request; - } - - public long getRequestId() { - return requestId; - } - - public UaResponseMessageType getResponse() { - return response; - } - - public boolean isServiceFault() { - return serviceFault; - } - - @Override - public String toString() { - ToStringHelper helper = MoreObjects.toStringHelper(this) - .add("requestId", requestId) - .add("request", request.getClass().getSimpleName()) - .add("response", response.getClass().getSimpleName()); - - if (serviceFault) { - helper.add("result", response.getResponseHeader().getServiceResult()); - } - - return helper.toString(); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/SessionServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/SessionServiceSet.java deleted file mode 100644 index 428ea2c2e..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/SessionServiceSet.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface SessionServiceSet { - - default void onCreateSession(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onActivateSession(ServiceRequest serviceRequest) throws UaException { - - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onCloseSession(ServiceRequest serviceRequest) throws UaException { - - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onCancel(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/SubscriptionServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/SubscriptionServiceSet.java deleted file mode 100644 index 3505c45bb..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/SubscriptionServiceSet.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface SubscriptionServiceSet { - - default void onCreateSubscription(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onModifySubscription(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onDeleteSubscriptions(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onTransferSubscriptions(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onSetPublishingMode(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onPublish(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onRepublish(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ViewServiceSet.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ViewServiceSet.java deleted file mode 100644 index 91336e888..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/services/ViewServiceSet.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.services; - -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; - -public interface ViewServiceSet { - - default void onBrowse(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onBrowseNext(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onTranslateBrowsePaths(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onRegisterNodes(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - - default void onUnregisterNodes(ServiceRequest serviceRequest) throws UaException { - serviceRequest.setServiceFault(StatusCodes.Bad_ServiceUnsupported); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/ServerChannelManager.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/ServerChannelManager.java deleted file mode 100644 index dc3edcdce..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/ServerChannelManager.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.transport; - -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; - -import com.google.common.collect.ConcurrentHashMultiset; -import com.google.common.collect.Multiset; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.logging.LoggingHandler; -import org.eclipse.milo.opcua.stack.core.Stack; -import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; -import org.eclipse.milo.opcua.stack.core.util.AsyncSemaphore; -import org.eclipse.milo.opcua.stack.core.util.Unit; -import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.eclipse.milo.opcua.stack.server.transport.http.OpcServerHttpChannelInitializer; -import org.eclipse.milo.opcua.stack.server.transport.tcp.OpcServerTcpChannelInitializer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ServerChannelManager { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final AsyncSemaphore semaphore = new AsyncSemaphore(1); - - private final Multiset addresses = ConcurrentHashMultiset.create(); - private final Map channels = new ConcurrentHashMap<>(); - - private final UaStackServer stackServer; - - public ServerChannelManager(UaStackServer stackServer) { - this.stackServer = stackServer; - } - - public CompletableFuture bind(EndpointConfiguration endpoint) { - CompletableFuture future = new CompletableFuture<>(); - - semaphore.acquire().thenApply(permit -> { - future.whenComplete((u, ex) -> permit.release()); - - InetSocketAddress bindAddress = new InetSocketAddress( - endpoint.getBindAddress(), - endpoint.getBindPort() - ); - - if (channels.containsKey(bindAddress)) { - return future.complete(Unit.VALUE); - } else { - logger.debug("binding to {}", bindAddress); - - CompletableFuture bootstrap = bootstrap( - stackServer, - bindAddress, - endpoint.getTransportProfile() - ); - - return bootstrap.whenComplete((channel, ex) -> { - if (channel != null) { - addresses.add(bindAddress); - channels.put(bindAddress, channel); - future.complete(Unit.VALUE); - } else { - future.completeExceptionally(ex); - } - }); - } - }); - - return future; - } - - public CompletableFuture unbind(EndpointConfiguration endpoint) { - CompletableFuture future = new CompletableFuture<>(); - - semaphore.acquire().thenAccept(permit -> { - future.whenComplete((u, ex) -> permit.release()); - - InetSocketAddress bindAddress = new InetSocketAddress( - endpoint.getBindAddress(), - endpoint.getBindPort() - ); - - if (addresses.remove(bindAddress, 1) == 1) { - logger.debug("unbinding from {}", bindAddress); - - Channel channel = channels.remove(bindAddress); - - if (channel != null) { - channel.close(); - } - } - - future.complete(Unit.VALUE); - }); - - return future; - } - - private static CompletableFuture bootstrap( - UaStackServer stackServer, - InetSocketAddress bindAddress, - TransportProfile transportProfile) { - - ChannelInitializer initializer; - - if (transportProfile == TransportProfile.TCP_UASC_UABINARY) { - initializer = new OpcServerTcpChannelInitializer(stackServer); - } else { - initializer = new OpcServerHttpChannelInitializer(stackServer); - } - - ServerBootstrap bootstrap = new ServerBootstrap(); - - bootstrap.group(Stack.sharedEventLoop()) - .handler(new LoggingHandler(ServerChannelManager.class)) - .channel(NioServerSocketChannel.class) - .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) - .childOption(ChannelOption.TCP_NODELAY, true) - .childHandler(initializer); - - CompletableFuture channelFuture = new CompletableFuture<>(); - - bootstrap.bind(bindAddress).addListener((ChannelFutureListener) future -> { - if (future.isSuccess()) { - Channel channel = future.channel(); - - channelFuture.complete(channel); - } else { - channelFuture.completeExceptionally(future.cause()); - } - }); - - return channelFuture; - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/http/OpcServerHttpChannelInitializer.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/http/OpcServerHttpChannelInitializer.java deleted file mode 100644 index 82289fa95..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/http/OpcServerHttpChannelInitializer.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.transport.http; - -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.util.Objects; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.channel.socket.SocketChannel; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.codec.http.HttpHeaderValues; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpServerCodec; -import io.netty.handler.codec.http.HttpVersion; -import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; -import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler; -import io.netty.handler.logging.LogLevel; -import io.netty.handler.logging.LoggingHandler; -import io.netty.handler.ssl.ClientAuth; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import org.eclipse.milo.opcua.stack.core.Stack; -import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.eclipse.milo.opcua.stack.server.transport.RateLimitingHandler; -import org.eclipse.milo.opcua.stack.server.transport.websocket.OpcServerWebSocketFrameHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class OpcServerHttpChannelInitializer extends ChannelInitializer { - - private SslContext sslContext = null; - - private final UaStackServer stackServer; - - public OpcServerHttpChannelInitializer(UaStackServer stackServer) { - this.stackServer = stackServer; - - KeyPair keyPair = stackServer.getConfig().getHttpsKeyPair().orElse(null); - X509Certificate[] httpsCertificate = stackServer.getConfig().getHttpsCertificateChain().orElse(null); - - if (keyPair != null && httpsCertificate != null) { - try { - PrivateKey privateKey = keyPair.getPrivate(); - - sslContext = SslContextBuilder - .forServer(privateKey, httpsCertificate) - .clientAuth(ClientAuth.NONE) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .build(); - } catch (Exception e) { - LoggerFactory.getLogger(OpcServerHttpChannelInitializer.class) - .error("Error configuration SslContext: {}", e.getMessage(), e); - } - } else { - LoggerFactory.getLogger(OpcServerHttpChannelInitializer.class) - .warn("HTTPS KeyPair and/or Certificate not configured; falling back to plaintext..."); - } - } - - - @Override - protected void initChannel(SocketChannel channel) { - stackServer.registerConnectedChannel(channel); - - channel.closeFuture().addListener(future -> stackServer.unregisterConnectedChannel(channel)); - - channel.pipeline().addLast(RateLimitingHandler.getInstance()); - - if (sslContext != null) { - channel.pipeline().addLast(sslContext.newHandler(channel.alloc())); - } - - channel.pipeline().addLast(new LoggingHandler(LogLevel.TRACE)); - channel.pipeline().addLast(new HttpServerCodec()); - - // TODO configure maxContentLength based on MaxRequestSize? - channel.pipeline().addLast(new HttpObjectAggregator(Integer.MAX_VALUE)); - channel.pipeline().addLast(new OpcHttpTransportInterceptor(stackServer)); - } - - private static class OpcHttpTransportInterceptor extends SimpleChannelInboundHandler { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final UaStackServer stackServer; - - public OpcHttpTransportInterceptor(UaStackServer stackServer) { - this.stackServer = stackServer; - } - - @Override - protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest httpRequest) { - String host = httpRequest.headers().get(HttpHeaderNames.HOST); - String uri = httpRequest.uri(); - - logger.debug("host={} uri={}", host, uri); - - boolean endpointMatch = stackServer.getEndpointDescriptions() - .stream() - .anyMatch(endpoint -> - Objects.equals( - uri, - EndpointUtil.getPath(endpoint.getEndpointUrl())) - ); - - if (!endpointMatch) { - logger.debug("unrecognized endpoint URL: " + uri); - - HttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, - HttpResponseStatus.NOT_FOUND - ); - - ctx.channel().writeAndFlush(response) - .addListener(future -> ctx.close()); - - return; - } - - if (Objects.equals(httpRequest.method(), HttpMethod.GET) && - "websocket".equalsIgnoreCase(httpRequest.headers().get(HttpHeaderValues.UPGRADE))) { - - logger.debug("intercepted WebSocket upgrade"); - - ctx.channel().pipeline().remove(this); - - ctx.channel().pipeline().addLast(new WebSocketServerCompressionHandler()); - - // TODO configure webSocketPath based on path component of endpoint URL? - ctx.channel().pipeline().addLast(new WebSocketServerProtocolHandler( - "/ws", - String.format("%s, %s", Stack.WSS_PROTOCOL_BINARY, Stack.WSS_PROTOCOL_JSON), - true - )); - - ctx.channel().pipeline().addLast(new OpcServerWebSocketFrameHandler(stackServer)); - - httpRequest.retain(); - ctx.executor().execute(() -> ctx.fireChannelRead(httpRequest)); - } else if (Objects.equals(httpRequest.method(), HttpMethod.POST)) { - logger.debug("intercepted HTTP POST"); - - ctx.channel().pipeline().remove(this); - ctx.channel().pipeline().addLast(new OpcServerHttpRequestHandler(stackServer)); - - httpRequest.retain(); - ctx.executor().execute(() -> ctx.pipeline().fireChannelRead(httpRequest)); - } else { - HttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, - HttpResponseStatus.BAD_REQUEST - ); - - ctx.channel().writeAndFlush(response) - .addListener(future -> ctx.close()); - } - } - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/http/OpcServerHttpRequestHandler.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/http/OpcServerHttpRequestHandler.java deleted file mode 100644 index 0d123862e..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/http/OpcServerHttpRequestHandler.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.transport.http; - -import java.net.InetSocketAddress; -import java.security.KeyPair; -import java.security.cert.X509Certificate; -import java.util.Objects; -import java.util.Optional; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.codec.http.HttpHeaderValues; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpVersion; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel; -import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryDecoder; -import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryEncoder; -import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; -import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; -import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; -import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; -import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; -import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; -import org.eclipse.milo.opcua.stack.core.util.BufferUtil; -import org.eclipse.milo.opcua.stack.core.util.DigestUtil; -import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class OpcServerHttpRequestHandler extends SimpleChannelInboundHandler { - - private static final String UABINARY_CONTENT_TYPE = - HttpHeaderValues.APPLICATION_OCTET_STREAM.toString(); - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final UaStackServer stackServer; - - OpcServerHttpRequestHandler(UaStackServer stackServer) { - this.stackServer = stackServer; - } - - @Override - protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest httpRequest) throws Exception { - String host = httpRequest.headers().get(HttpHeaderNames.HOST); - String uri = httpRequest.uri(); - String contentType = httpRequest.headers().get(HttpHeaderNames.CONTENT_TYPE); - String securityPolicyUri = httpRequest.headers().get("OPCUA-SecurityPolicy"); - - logger.debug("host={} uri={} contentType={} securityPolicy={}", host, uri, contentType, securityPolicyUri); - - SecurityPolicy securityPolicy = securityPolicyUri != null ? - SecurityPolicy.fromUri(securityPolicyUri) : - SecurityPolicy.None; - - MessageSecurityMode securityMode = securityPolicy == SecurityPolicy.None ? - MessageSecurityMode.None : - MessageSecurityMode.Sign; - - EndpointDescription endpoint = stackServer.getEndpointDescriptions() - .stream() - .filter(e -> { - // TODO use contentType to determine which TransportProfile to match - boolean transportMatch = Objects.equals( - e.getTransportProfileUri(), - TransportProfile.HTTPS_UABINARY.getUri() - ); - - boolean pathMatch = Objects.equals( - EndpointUtil.getPath(e.getEndpointUrl()), - uri - ); - - boolean securityPolicyMatch = Objects.equals( - e.getSecurityPolicyUri(), - securityPolicy.getUri() - ); - - boolean securityModeMatch = Objects.equals( - e.getSecurityMode(), - securityMode - ); - - return transportMatch && pathMatch && securityPolicyMatch && securityModeMatch; - }) - .findFirst() - .orElseThrow(() -> - new UaException( - StatusCodes.Bad_TcpEndpointUrlInvalid, - "unrecognized endpoint uri: " + uri)); - - - ServerSecureChannel secureChannel = new ServerSecureChannel(); - secureChannel.setChannelId(0L); // TODO shared id per endpoint URL / path? - secureChannel.setSecurityPolicy(securityPolicy); - secureChannel.setMessageSecurityMode(securityMode); - - ByteString thumbprint = ByteString.of(DigestUtil.sha1(endpoint.getServerCertificate().bytesOrEmpty())); - - Optional certificateChain = stackServer.getConfig() - .getCertificateManager() - .getCertificateChain(thumbprint); - - Optional keyPair = stackServer.getConfig() - .getCertificateManager() - .getKeyPair(thumbprint); - - certificateChain.ifPresent(chain -> { - secureChannel.setLocalCertificateChain(chain); - secureChannel.setLocalCertificate(chain[0]); - }); - - keyPair.ifPresent(secureChannel::setKeyPair); - - OpcUaBinaryDecoder decoder = new OpcUaBinaryDecoder(stackServer.getEncodingContext()); - decoder.setBuffer(httpRequest.content()); - - try { - UaRequestMessageType request = (UaRequestMessageType) decoder.decodeMessage(null); - UInteger requestHandle = request.getRequestHeader().getRequestHandle(); - - InetSocketAddress remoteSocketAddress = - (InetSocketAddress) ctx.channel().remoteAddress(); - - ServiceRequest serviceRequest = new ServiceRequest( - stackServer, - request, - endpoint, - secureChannel.getChannelId(), - remoteSocketAddress.getAddress(), - null - ); - - serviceRequest.getFuture().whenComplete((response, fault) -> { - if (response != null) { - sendServiceResponse(ctx, request, response); - } else { - sendServiceFault(ctx, requestHandle, fault); - } - }); - - stackServer.onServiceRequest(uri, serviceRequest); - } catch (Throwable t) { - logger.error("Error decoding UaRequestMessage", t); - - sendServiceFault(ctx, null, t); - } - } - - private void sendServiceResponse( - ChannelHandlerContext ctx, - UaRequestMessageType request, - UaResponseMessageType response) { - - ByteBuf contentBuffer = BufferUtil.pooledBuffer(); - - // TODO switch on transport profile for binary vs xml encoding - OpcUaBinaryEncoder binaryEncoder = new OpcUaBinaryEncoder(stackServer.getEncodingContext()); - binaryEncoder.setBuffer(contentBuffer); - binaryEncoder.encodeMessage(null, response); - - FullHttpResponse httpResponse = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, - HttpResponseStatus.OK, - contentBuffer - ); - - httpResponse.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); - httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, UABINARY_CONTENT_TYPE); - httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, contentBuffer.readableBytes()); - - ctx.writeAndFlush(httpResponse); - } - - private void sendServiceFault( - ChannelHandlerContext ctx, - UInteger requestHandle, - Throwable fault) { - - StatusCode statusCode = UaException.extract(fault) - .map(UaException::getStatusCode) - .orElse(StatusCode.BAD); - - ServiceFault serviceFault = new ServiceFault( - new ResponseHeader( - DateTime.now(), - requestHandle, - statusCode, - null, - null, - null - ) - ); - - ByteBuf contentBuffer = BufferUtil.pooledBuffer(); - - // TODO switch on transport profile for binary vs xml encoding - OpcUaBinaryEncoder binaryEncoder = new OpcUaBinaryEncoder(stackServer.getEncodingContext()); - binaryEncoder.setBuffer(contentBuffer); - binaryEncoder.encodeMessage(null, serviceFault); - - FullHttpResponse httpResponse = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, - HttpResponseStatus.OK, - contentBuffer - ); - - httpResponse.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); - httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, UABINARY_CONTENT_TYPE); - httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, contentBuffer.readableBytes()); - - ctx.writeAndFlush(httpResponse); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/tcp/OpcServerTcpChannelInitializer.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/tcp/OpcServerTcpChannelInitializer.java deleted file mode 100644 index e0be1554f..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/tcp/OpcServerTcpChannelInitializer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.transport.tcp; - -import io.netty.channel.ChannelInitializer; -import io.netty.channel.socket.SocketChannel; -import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.eclipse.milo.opcua.stack.server.transport.RateLimitingHandler; -import org.eclipse.milo.opcua.stack.server.transport.uasc.UascServerHelloHandler; - -public class OpcServerTcpChannelInitializer extends ChannelInitializer { - - private final UaStackServer stackServer; - - public OpcServerTcpChannelInitializer(UaStackServer stackServer) { - this.stackServer = stackServer; - } - - @Override - protected void initChannel(SocketChannel channel) { - stackServer.registerConnectedChannel(channel); - - channel.closeFuture().addListener(future -> stackServer.unregisterConnectedChannel(channel)); - - channel.pipeline().addLast(RateLimitingHandler.getInstance()); - channel.pipeline().addLast(new UascServerHelloHandler(stackServer, TransportProfile.TCP_UASC_UABINARY)); - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/uasc/UascServerSymmetricHandler.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/uasc/UascServerSymmetricHandler.java deleted file mode 100644 index c9d6d7433..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/uasc/UascServerSymmetricHandler.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.transport.uasc; - -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.CompositeByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.UaSerializationException; -import org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder; -import org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder.EncodedMessage; -import org.eclipse.milo.opcua.stack.core.channel.MessageAbortException; -import org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException; -import org.eclipse.milo.opcua.stack.core.channel.MessageEncodeException; -import org.eclipse.milo.opcua.stack.core.channel.SerializationQueue; -import org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel; -import org.eclipse.milo.opcua.stack.core.channel.headers.HeaderDecoder; -import org.eclipse.milo.opcua.stack.core.channel.messages.MessageType; -import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; -import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; -import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; -import org.eclipse.milo.opcua.stack.core.util.BufferUtil; -import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.eclipse.milo.opcua.stack.server.services.ServiceRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - -public class UascServerSymmetricHandler extends ByteToMessageDecoder implements HeaderDecoder { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private List chunkBuffers; - - private final int maxChunkCount; - private final int maxChunkSize; - - private final UaStackServer stackServer; - private final SerializationQueue serializationQueue; - private final ServerSecureChannel secureChannel; - - UascServerSymmetricHandler( - UaStackServer stackServer, - SerializationQueue serializationQueue, - ServerSecureChannel secureChannel) { - - this.stackServer = stackServer; - this.serializationQueue = serializationQueue; - this.secureChannel = secureChannel; - - maxChunkCount = serializationQueue.getParameters().getLocalMaxChunkCount(); - maxChunkSize = serializationQueue.getParameters().getLocalReceiveBufferSize(); - - chunkBuffers = new ArrayList<>(maxChunkCount); - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { - if (buffer.readableBytes() >= HEADER_LENGTH) { - int messageLength = getMessageLength(buffer, maxChunkSize); - - if (buffer.readableBytes() >= messageLength) { - MessageType messageType = MessageType.fromMediumInt( - buffer.getMediumLE(buffer.readerIndex()) - ); - - if (messageType == MessageType.SecureMessage) { - onSecureMessage(ctx, buffer.readSlice(messageLength)); - } else { - ctx.fireChannelRead(buffer.readRetainedSlice(messageLength)); - } - } - } - } - - private void onSecureMessage(ChannelHandlerContext ctx, ByteBuf buffer) throws UaException { - buffer.skipBytes(3); // Skip messageType - - char chunkType = (char) buffer.readByte(); - - if (chunkType == 'A') { - chunkBuffers.forEach(ByteBuf::release); - chunkBuffers.clear(); - } else { - buffer.skipBytes(4); // Skip messageSize - - long secureChannelId = buffer.readUnsignedIntLE(); - if (secureChannelId != secureChannel.getChannelId()) { - throw new UaException(StatusCodes.Bad_SecureChannelIdInvalid, - "invalid secure channel id: " + secureChannelId); - } - - int chunkSize = buffer.readerIndex(0).readableBytes(); - if (chunkSize > maxChunkSize) { - throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, - String.format("max chunk size exceeded (%s)", maxChunkSize)); - } - - chunkBuffers.add(buffer.retain()); - - if (maxChunkCount > 0 && chunkBuffers.size() > maxChunkCount) { - throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, - String.format("max chunk count exceeded (%s)", maxChunkCount)); - } - - if (chunkType == 'F') { - final List buffersToDecode = chunkBuffers; - chunkBuffers = new ArrayList<>(); - - serializationQueue.decode((binaryDecoder, chunkDecoder) -> { - ByteBuf message; - long requestId; - - try { - ChunkDecoder.DecodedMessage decodedMessage = - chunkDecoder.decodeSymmetric(secureChannel, buffersToDecode); - - message = decodedMessage.getMessage(); - requestId = decodedMessage.getRequestId(); - } catch (MessageAbortException e) { - logger.warn( - "Received message abort chunk; error={}, reason={}", - e.getStatusCode(), e.getMessage() - ); - return; - } catch (MessageDecodeException e) { - logger.error("Error decoding symmetric message", e); - - ctx.close(); - return; - } - - try { - UaRequestMessageType request = (UaRequestMessageType) binaryDecoder - .setBuffer(message) - .decodeMessage(null); - - String endpointUrl = ctx.channel() - .attr(UascServerHelloHandler.ENDPOINT_URL_KEY) - .get(); - - EndpointDescription endpoint = ctx.channel() - .attr(UascServerAsymmetricHandler.ENDPOINT_KEY) - .get(); - - String path = EndpointUtil.getPath(endpointUrl); - - InetSocketAddress remoteSocketAddress = - (InetSocketAddress) ctx.channel().remoteAddress(); - - ServiceRequest serviceRequest = new ServiceRequest( - stackServer, - request, - endpoint, - secureChannel.getChannelId(), - remoteSocketAddress.getAddress(), - secureChannel.getRemoteCertificateBytes() - ); - - serviceRequest.getFuture().whenComplete((response, fault) -> { - if (response != null) { - sendServiceResponse(ctx, requestId, request, response); - } else { - UInteger requestHandle = request.getRequestHeader().getRequestHandle(); - - sendServiceFault(ctx, requestId, requestHandle, fault); - } - }); - - stackServer.onServiceRequest(path, serviceRequest); - } catch (UaSerializationException e) { - logger.error("Error decoding UaRequestMessage", e); - - sendServiceFault(ctx, requestId, uint(0), e); - } catch (Throwable t) { - logger.error("Unexpected error servicing UaRequestMessage", t); - - long statusCode = UaException.extractStatusCode(t) - .map(StatusCode::getValue) - .orElse(StatusCodes.Bad_UnexpectedError); - - sendServiceFault(ctx, requestId, uint(0), new UaException(statusCode, t)); - } finally { - message.release(); - buffersToDecode.clear(); - } - }); - } - } - } - - private void sendServiceResponse( - ChannelHandlerContext ctx, - long requestId, - UaRequestMessageType request, - UaResponseMessageType response) { - - serializationQueue.encode((binaryEncoder, chunkEncoder) -> { - ByteBuf messageBuffer = BufferUtil.pooledBuffer(); - - try { - binaryEncoder.setBuffer(messageBuffer); - binaryEncoder.encodeMessage(null, response); - - checkMessageSize(messageBuffer); - - EncodedMessage encodedMessage = chunkEncoder.encodeSymmetric( - secureChannel, - requestId, - messageBuffer, - MessageType.SecureMessage - ); - - CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); - - for (ByteBuf chunk : encodedMessage.getMessageChunks()) { - chunkComposite.addComponent(chunk); - chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); - } - - ctx.writeAndFlush(chunkComposite, ctx.voidPromise()); - } catch (MessageEncodeException e) { - logger.error("Error encoding {}: {}", response, e.getMessage(), e); - - UInteger requestHandle = request.getRequestHeader().getRequestHandle(); - - sendServiceFault(ctx, requestId, requestHandle, e); - } catch (UaSerializationException e) { - logger.error("Error serializing response: {}", e.getStatusCode(), e); - - UInteger requestHandle = request.getRequestHeader().getRequestHandle(); - - sendServiceFault(ctx, requestId, requestHandle, e); - } finally { - messageBuffer.release(); - } - }); - } - - private void sendServiceFault( - ChannelHandlerContext ctx, - long requestId, - UInteger requestHandle, - Throwable fault) { - - StatusCode statusCode = UaException.extract(fault) - .map(UaException::getStatusCode) - .orElse(StatusCode.BAD); - - ServiceFault serviceFault = new ServiceFault( - new ResponseHeader( - DateTime.now(), - requestHandle, - statusCode, - null, - null, - null - ) - ); - - serializationQueue.encode((binaryEncoder, chunkEncoder) -> { - ByteBuf messageBuffer = BufferUtil.pooledBuffer(); - - try { - binaryEncoder.setBuffer(messageBuffer); - binaryEncoder.encodeMessage(null, serviceFault); - - checkMessageSize(messageBuffer); - - EncodedMessage encodedMessage = chunkEncoder.encodeSymmetric( - secureChannel, - requestId, - messageBuffer, - MessageType.SecureMessage - ); - - CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); - - for (ByteBuf chunk : encodedMessage.getMessageChunks()) { - chunkComposite.addComponent(chunk); - chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); - } - - ctx.writeAndFlush(chunkComposite, ctx.voidPromise()); - } catch (MessageEncodeException e) { - logger.error("Error encoding {}: {}", serviceFault, e.getMessage(), e); - } catch (UaSerializationException e) { - logger.error("Error serializing ServiceFault: {}", e.getStatusCode(), e); - } finally { - messageBuffer.release(); - } - }); - } - - private void checkMessageSize(ByteBuf messageBuffer) throws UaSerializationException { - int messageSize = messageBuffer.readableBytes(); - int remoteMaxMessageSize = serializationQueue.getParameters().getRemoteMaxMessageSize(); - - if (remoteMaxMessageSize > 0 && messageSize > remoteMaxMessageSize) { - throw new UaSerializationException( - StatusCodes.Bad_ResponseTooLarge, - "response exceeds remote max message size: " + - messageSize + " > " + remoteMaxMessageSize); - } - } - -} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/websocket/OpcServerWebSocketFrameHandler.java b/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/websocket/OpcServerWebSocketFrameHandler.java deleted file mode 100644 index e0e008f2d..000000000 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/websocket/OpcServerWebSocketFrameHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.server.transport.websocket; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; -import org.eclipse.milo.opcua.stack.core.Stack; -import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.eclipse.milo.opcua.stack.server.transport.uasc.UascServerHelloHandler; - -import static io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler.HandshakeComplete; - -public class OpcServerWebSocketFrameHandler extends SimpleChannelInboundHandler { - - private String subprotocol; - - private final UaStackServer stackServer; - - public OpcServerWebSocketFrameHandler(UaStackServer stackServer) { - this.stackServer = stackServer; - } - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object event) throws Exception { - if (event instanceof HandshakeComplete) { - HandshakeComplete handshake = (HandshakeComplete) event; - - subprotocol = handshake.selectedSubprotocol(); - - if (Stack.WSS_PROTOCOL_BINARY.equalsIgnoreCase(subprotocol)) { - UascServerHelloHandler helloHandler = new UascServerHelloHandler( - stackServer, - TransportProfile.WSS_UASC_UABINARY - ); - - ctx.channel().pipeline().addLast(helloHandler); - } else { - throw new IllegalArgumentException("subprotocol: " + subprotocol); - } - } - - super.userEventTriggered(ctx, event); - } - - @Override - protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msg) { - if (Stack.WSS_PROTOCOL_BINARY.equalsIgnoreCase(subprotocol)) { - // Pass the binary contents to the UA Secure Conversation handlers - - ctx.fireChannelRead(msg.content().retain()); - } else if (Stack.WSS_PROTOCOL_JSON.equalsIgnoreCase(subprotocol)) { - // TODO End of the pipeline; decode and deliver - String text = ((TextWebSocketFrame) msg).text(); - - throw new IllegalArgumentException("subprotocol: " + subprotocol); - } else { - ctx.close(); - } - } - -} diff --git a/opc-ua-stack/stack-tests/pom.xml b/opc-ua-stack/stack-tests/pom.xml index 8e3cee682..c2242579a 100644 --- a/opc-ua-stack/stack-tests/pom.xml +++ b/opc-ua-stack/stack-tests/pom.xml @@ -28,16 +28,10 @@ org.eclipse.milo - stack-client - ${project.version} - test - - - org.eclipse.milo - stack-server - ${project.version} - test + transport + 2.0.0-SNAPSHOT + org.testng testng diff --git a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ChunkSerializationTest.java b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ChunkSerializationTest.java index 6c6f19ede..443823b61 100644 --- a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ChunkSerializationTest.java +++ b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ChunkSerializationTest.java @@ -17,7 +17,6 @@ import io.netty.buffer.ByteBuf; import io.netty.util.ReferenceCountUtil; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel; import org.eclipse.milo.opcua.stack.core.channel.ChannelParameters; import org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder; import org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder; @@ -31,6 +30,7 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; import org.eclipse.milo.opcua.stack.core.util.BufferUtil; import org.eclipse.milo.opcua.stack.core.util.LongSequence; +import org.eclipse.milo.opcua.stack.transport.client.uasc.ClientSecureChannel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.DataProvider; @@ -48,9 +48,9 @@ public class ChunkSerializationTest extends SecureChannelFixture { Security.addProvider(new BouncyCastleProvider()); } - private Logger logger = LoggerFactory.getLogger(getClass()); + private final Logger logger = LoggerFactory.getLogger(getClass()); - private ChannelParameters smallParameters = new ChannelParameters( + private final ChannelParameters smallParameters = new ChannelParameters( 32 * 8196, 8196, 8196, @@ -61,7 +61,7 @@ public class ChunkSerializationTest extends SecureChannelFixture { 64 ); - private ChannelParameters defaultParameters = new ChannelParameters( + private final ChannelParameters defaultParameters = new ChannelParameters( DEFAULT_MAX_MESSAGE_SIZE, DEFAULT_MAX_CHUNK_SIZE, DEFAULT_MAX_CHUNK_SIZE, @@ -72,7 +72,7 @@ public class ChunkSerializationTest extends SecureChannelFixture { 0 ); - private ChannelParameters unlimitedChunkCountParameters = new ChannelParameters( + private final ChannelParameters unlimitedChunkCountParameters = new ChannelParameters( EncodingLimits.DEFAULT_MAX_MESSAGE_SIZE, EncodingLimits.DEFAULT_MAX_CHUNK_SIZE, EncodingLimits.DEFAULT_MAX_CHUNK_SIZE, @@ -83,7 +83,7 @@ public class ChunkSerializationTest extends SecureChannelFixture { 0 ); - private ChannelParameters unlimitedMessageSizeParameters = new ChannelParameters( + private final ChannelParameters unlimitedMessageSizeParameters = new ChannelParameters( 0, EncodingLimits.DEFAULT_MAX_CHUNK_SIZE, EncodingLimits.DEFAULT_MAX_CHUNK_SIZE, @@ -140,12 +140,7 @@ public void testAsymmetric4096() throws Exception { ClientSecureChannel clientChannel = (ClientSecureChannel) channels[0]; ServerSecureChannel serverChannel = (ServerSecureChannel) channels[1]; - clientChannel - .attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE) - .setIfAbsent(new LongSequence(1L, UInteger.MAX_VALUE)); - - LongSequence requestId = clientChannel - .attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).get(); + LongSequence requestId = new LongSequence(1L, UInteger.MAX_VALUE); for (int messageSize = 0; messageSize < 512; messageSize++) { byte[] messageBytes = new byte[messageSize]; @@ -203,12 +198,7 @@ public void testSymmetric4096() throws Exception { ClientSecureChannel clientChannel = (ClientSecureChannel) channels[0]; ServerSecureChannel serverChannel = (ServerSecureChannel) channels[1]; - clientChannel - .attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE) - .setIfAbsent(new LongSequence(1L, UInteger.MAX_VALUE)); - - LongSequence requestId = clientChannel - .attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).get(); + LongSequence requestId = new LongSequence(1L, UInteger.MAX_VALUE); for (int messageSize = 0; messageSize < 1024; messageSize++) { byte[] messageBytes = new byte[messageSize]; @@ -278,12 +268,7 @@ public void testAsymmetricMessage(SecurityPolicy securityPolicy, ClientSecureChannel clientChannel = (ClientSecureChannel) channels[0]; ServerSecureChannel serverChannel = (ServerSecureChannel) channels[1]; - clientChannel - .attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE) - .setIfAbsent(new LongSequence(1L, UInteger.MAX_VALUE)); - - LongSequence requestId = clientChannel - .attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).get(); + LongSequence requestId = new LongSequence(1L, UInteger.MAX_VALUE); byte[] messageBytes = new byte[messageSize]; for (int i = 0; i < messageBytes.length; i++) { @@ -376,12 +361,7 @@ public void testSymmetricMessage(SecurityPolicy securityPolicy, ClientSecureChannel clientChannel = (ClientSecureChannel) channels[0]; ServerSecureChannel serverChannel = (ServerSecureChannel) channels[1]; - clientChannel - .attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE) - .setIfAbsent(new LongSequence(1L, UInteger.MAX_VALUE)); - - LongSequence requestId = clientChannel - .attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).get(); + LongSequence requestId = new LongSequence(1L, UInteger.MAX_VALUE); byte[] messageBytes = new byte[messageSize]; for (int i = 0; i < messageBytes.length; i++) { diff --git a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ClientCertificateValidatorIT.java b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ClientCertificateValidatorIT.java index 07cf0ee31..c8c374be3 100644 --- a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ClientCertificateValidatorIT.java +++ b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ClientCertificateValidatorIT.java @@ -1,76 +1,76 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack; - -import java.security.cert.X509Certificate; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.milo.opcua.stack.client.UaStackClientConfigBuilder; -import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; - -public class ClientCertificateValidatorIT extends StackIntegrationTest { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final CountDownLatch latch = new CountDownLatch(1); - - private final ClientCertificateValidator validator = new ClientCertificateValidator() { - - @Override - public void validateCertificateChain(List certificateChain) throws UaException { - X509Certificate certificate = certificateChain.get(0); - logger.info("verifyTrustChain: {}", certificate.getSubjectX500Principal()); - latch.countDown(); - } - - @Override - public void validateCertificateChain( - List certificateChain, - String applicationUri, - String... validHostNames - ) throws UaException { - - validateCertificateChain(certificateChain); - } - - }; - - @Test - public void testClientCertificateValidatorIsCalled() throws InterruptedException { - assertTrue(latch.await(10, TimeUnit.SECONDS), "latch not obtained!"); - } - - @Override - protected UaStackClientConfigBuilder configureClient(UaStackClientConfigBuilder builder) { - return builder - .setCertificate(clientCertificate) - .setCertificateValidator(validator); - } - - @Override - protected EndpointDescription selectEndpoint(List endpoints) { - return endpoints.stream() - .filter(e -> !SecurityPolicy.None.getUri().equals(e.getSecurityPolicyUri())) - .findFirst() - .orElseThrow(() -> new RuntimeException("no secure endpoint found!")); - } - -} +///* +// * Copyright (c) 2019 the Eclipse Milo Authors +// * +// * This program and the accompanying materials are made +// * available under the terms of the Eclipse Public License 2.0 +// * which is available at https://www.eclipse.org/legal/epl-2.0/ +// * +// * SPDX-License-Identifier: EPL-2.0 +// */ +// +//package org.eclipse.milo.opcua.stack; +// +//import java.security.cert.X509Certificate; +//import java.util.List; +//import java.util.concurrent.CountDownLatch; +//import java.util.concurrent.TimeUnit; +// +//import org.eclipse.milo.opcua.stack.client.UaStackClientConfigBuilder; +//import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator; +//import org.eclipse.milo.opcua.stack.core.UaException; +//import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +//import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.testng.annotations.Test; +// +//import static org.testng.Assert.assertTrue; +// +//public class ClientCertificateValidatorIT extends StackIntegrationTest { +// +// private final Logger logger = LoggerFactory.getLogger(getClass()); +// +// private final CountDownLatch latch = new CountDownLatch(1); +// +// private final ClientCertificateValidator validator = new ClientCertificateValidator() { +// +// @Override +// public void validateCertificateChain(List certificateChain) throws UaException { +// X509Certificate certificate = certificateChain.get(0); +// logger.info("verifyTrustChain: {}", certificate.getSubjectX500Principal()); +// latch.countDown(); +// } +// +// @Override +// public void validateCertificateChain( +// List certificateChain, +// String applicationUri, +// String... validHostNames +// ) throws UaException { +// +// validateCertificateChain(certificateChain); +// } +// +// }; +// +// @Test +// public void testClientCertificateValidatorIsCalled() throws InterruptedException { +// assertTrue(latch.await(10, TimeUnit.SECONDS), "latch not obtained!"); +// } +// +// @Override +// protected UaStackClientConfigBuilder configureClient(UaStackClientConfigBuilder builder) { +// return builder +// .setCertificate(clientCertificate) +// .setCertificateValidator(validator); +// } +// +// @Override +// protected EndpointDescription selectEndpoint(List endpoints) { +// return endpoints.stream() +// .filter(e -> !SecurityPolicy.None.getUri().equals(e.getSecurityPolicyUri())) +// .findFirst() +// .orElseThrow(() -> new RuntimeException("no secure endpoint found!")); +// } +// +//} diff --git a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ClientServerTest.java b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ClientServerTest.java index dc6c8c767..a97821abf 100644 --- a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ClientServerTest.java +++ b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/ClientServerTest.java @@ -1,627 +1,627 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack; - -import java.security.Security; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.eclipse.milo.opcua.stack.client.DiscoveryClient; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.core.AttributeId; -import org.eclipse.milo.opcua.stack.core.Stack; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; -import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; -import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; -import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; -import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; -import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; -import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; -import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; -import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; -import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; -import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; -import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; -import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; -import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; -import org.eclipse.milo.opcua.stack.core.types.builtin.XmlElement; -import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; -import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; -import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; -import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.ReadRequest; -import org.eclipse.milo.opcua.stack.core.types.structured.ReadResponse; -import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; -import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; -import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; -import org.eclipse.milo.opcua.stack.core.util.FutureUtils; -import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.eclipse.milo.opcua.stack.server.UaStackServerConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.AfterSuite; -import org.testng.annotations.BeforeSuite; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ubyte; -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ulong; -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ushort; -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; -import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.fail; - -public class ClientServerTest extends SecurityFixture { - - static { - Security.addProvider(new BouncyCastleProvider()); - - Stack.ConnectionLimits.RATE_LIMIT_ENABLED = false; - } - - private static final UInteger DEFAULT_TIMEOUT_HINT = uint(60000); - - @DataProvider - public Object[][] getVariants() { - return new Object[][]{ - {new Variant(true)}, - {new Variant((byte) 1)}, - {new Variant(ubyte(1))}, - {new Variant((short) 1)}, - {new Variant(ushort(1))}, - {new Variant(1)}, - {new Variant(uint(1))}, - {new Variant(1L)}, - {new Variant(ulong(1L))}, - {new Variant(3.14f)}, - {new Variant(6.12d)}, - {new Variant("hello, world")}, - {new Variant(DateTime.now())}, - {new Variant(UUID.randomUUID())}, - {new Variant(ByteString.of(new byte[]{1, 2, 3, 4}))}, - {new Variant(new XmlElement("hello"))}, - {new Variant(new NodeId(0, 42))}, - {new Variant(new ExpandedNodeId(ushort(1), "uri", uint(42), uint(1)))}, - {new Variant(StatusCode.GOOD)}, - {new Variant(new QualifiedName(0, "QualifiedName"))}, - {new Variant(LocalizedText.english("LocalizedText"))}, - {new Variant(ExtensionObject.encode( - new TestEncodingContext(), - new ReadValueId(NodeId.NULL_VALUE, uint(1), null, new QualifiedName(0, "DataEncoding")) - ))}, - }; - } - - private Logger logger = LoggerFactory.getLogger(getClass()); - - private EndpointDescription[] endpoints; - - private UaStackServer server; - - @BeforeSuite - public void setUpClientServer() throws Exception { - super.setUp(); - - UaStackServerConfig config = UaStackServerConfig.builder() - .setCertificateManager(serverCertificateManager) - .setCertificateValidator(serverCertificateValidator) - .setEndpoints(createEndpointConfigurations(serverCertificate)) - .build(); - - server = new UaStackServer(config); - - setReadRequestHandler(new Variant(42)); - - server.startup().get(); - - endpoints = DiscoveryClient.getEndpoints("opc.tcp://localhost:12685/test") - .get() - .toArray(new EndpointDescription[0]); - } - - @AfterSuite - public void tearDownClientServer() throws Exception { - server.shutdown().get(); - } - - private void setReadRequestHandler(Variant variant) { - server.addServiceHandler("/test", ReadRequest.TYPE_ID, service -> { - ReadRequest request = (ReadRequest) service.getRequest(); - - ResponseHeader header = new ResponseHeader( - DateTime.now(), - request.getRequestHeader().getRequestHandle(), - StatusCode.GOOD, - null, - null, - null - ); - - List nodesToRead = l(request.getNodesToRead()); - List results = Collections.nCopies(nodesToRead.size(), new DataValue(variant)); - - ReadResponse response = new ReadResponse(header, a(results, DataValue.class), null); - - service.setResponse(response); - }); - } - - @Test(dataProvider = "getVariants") - public void testClientServerRoundTrip_TestStack_NoSecurity(Variant input) throws Exception { - EndpointDescription endpoint = endpoints[0]; - - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - connectAndTest(input, client); - } - - @Test(dataProvider = "getVariants") - public void testClientServerRoundTrip_TestStack_Basic128Rsa15_Sign(Variant input) throws Exception { - EndpointDescription endpoint = endpoints[1]; - - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - connectAndTest(input, client); - } - - @Test(dataProvider = "getVariants") - public void testClientServerRoundTrip_TestStack_Basic256_Sign(Variant input) throws Exception { - EndpointDescription endpoint = endpoints[2]; - - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - connectAndTest(input, client); - } - - @Test(dataProvider = "getVariants") - public void testClientServerRoundTrip_TestStack_Basic256Sha256_Sign(Variant input) throws Exception { - EndpointDescription endpoint = endpoints[3]; - - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - connectAndTest(input, client); - } - - @Test(dataProvider = "getVariants") - public void testClientServerRoundTrip_TestStack_Basic128Rsa15_SignAndEncrypt(Variant input) throws Exception { - EndpointDescription endpoint = endpoints[4]; - - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - connectAndTest(input, client); - } - - @Test(dataProvider = "getVariants") - public void testClientServerRoundTrip_TestStack_Basic256_SignAndEncrypt(Variant input) throws Exception { - EndpointDescription endpoint = endpoints[5]; - - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - connectAndTest(input, client); - } - - @Test(dataProvider = "getVariants") - public void testClientServerRoundTrip_TestStack_Basic256Sha256_SignAndEncrypt(Variant input) throws Exception { - EndpointDescription endpoint = endpoints[6]; - - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - connectAndTest(input, client); - } - - @Test - public void testClientStateMachine() throws Exception { - EndpointDescription endpoint = endpoints[0]; - - Variant input = new Variant(42); - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - for (int i = 0; i < 1000; i++) { - client.connect().get(); - - RequestHeader header = new RequestHeader( - NodeId.NULL_VALUE, - DateTime.now(), - uint(i), - uint(0), - null, - DEFAULT_TIMEOUT_HINT, - null - ); - - ReadRequest request = new ReadRequest( - header, - 0.0, - TimestampsToReturn.Neither, - new ReadValueId[]{ - new ReadValueId( - NodeId.NULL_VALUE, - AttributeId.Value.uid(), - null, - null) - } - ); - - logger.debug("sending request: {}", request); - UaResponseMessageType response = client.sendRequest(request).get(); - logger.debug("got response: {}", response); - - client.disconnect().get(); - } - } - - @Test - public void testClientDisconnect() throws Exception { - EndpointDescription endpoint = endpoints[0]; - Variant input = new Variant(42); - - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - client.connect().get(); - - RequestHeader header = new RequestHeader( - NodeId.NULL_VALUE, - DateTime.now(), - uint(0), - uint(0), - null, - DEFAULT_TIMEOUT_HINT, - null - ); - - ReadRequest request = new ReadRequest( - header, - 0.0, - TimestampsToReturn.Neither, - new ReadValueId[]{ - new ReadValueId( - NodeId.NULL_VALUE, - AttributeId.Value.uid(), - null, - null) - } - ); - - logger.info("sending request: {}", request); - UaResponseMessageType response0 = client.sendRequest(request).get(); - logger.info("got response: {}", response0); - - client.disconnect().get(); - - assertThrows(() -> client.sendRequest(request).get()); - } - - @Test - public void testClientReconnect() throws Exception { - EndpointDescription endpoint = endpoints[0]; - Variant input = new Variant(42); - - logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); - - UaStackClient client = createClient(endpoint); - - client.connect().get(); - - RequestHeader header = new RequestHeader( - NodeId.NULL_VALUE, - DateTime.now(), - uint(0), - uint(0), - null, - DEFAULT_TIMEOUT_HINT, - null - ); - - ReadRequest request = new ReadRequest( - header, - 0.0, - TimestampsToReturn.Neither, - new ReadValueId[]{ - new ReadValueId( - NodeId.NULL_VALUE, - AttributeId.Value.uid(), - null, - null) - } - ); - - logger.info("sending request: {}", request); - UaResponseMessageType response0 = client.sendRequest(request).get(); - logger.info("got response: {}", response0); - - logger.info("initiating a reconnect by closing channel in server..."); - server.getConnectedChannels().forEach(c -> { - try { - c.close().await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - }); - - logger.info("sending request: {}", request); - try { - UaResponseMessageType response1 = client.sendRequest(request).get(); - logger.info("got response: {}", response1); - } catch (Exception e) { - // try again because close() above is a race condition - UaResponseMessageType response1 = client.sendRequest(request).get(); - logger.info("got response: {}", response1); - } - - client.disconnect().get(); - } - - @Test - public void testClientTimeout() throws Exception { - EndpointDescription endpoint = endpoints[0]; - - logger.info("SecurityPolicy={}, MessageSecurityMode={}", - SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode()); - - UaStackClientConfig config = UaStackClientConfig.builder() - .setEndpoint(endpoint) - .setKeyPair(clientKeyPair) - .setCertificate(clientCertificate) - .build(); - - UaStackClient client = UaStackClient.create(config); - client.connect().get(); - - server.addServiceHandler("/test", ReadRequest.TYPE_ID, service -> { - // intentionally do nothing so the request can timeout - logger.info("received {}; ignoring...", service.getRequest()); - }); - - RequestHeader header = new RequestHeader( - NodeId.NULL_VALUE, - DateTime.now(), - uint(0), - uint(0), - null, - uint(1000), - null - ); - - ReadRequest request = new ReadRequest( - header, - 0.0, - TimestampsToReturn.Neither, - new ReadValueId[]{ - new ReadValueId( - NodeId.NULL_VALUE, - AttributeId.Value.uid(), - null, - null) - } - ); - - try { - client.sendRequest(request).get(); - - fail("expected response to timeout"); - } catch (Throwable t) { - StatusCode statusCode = UaException - .extractStatusCode(t) - .orElse(StatusCode.BAD); - - assertEquals(statusCode.getValue(), StatusCodes.Bad_Timeout); - } - } - - private UaStackClient createClient(EndpointDescription endpoint) throws UaException { - UaStackClientConfig config = UaStackClientConfig.builder() - .setEndpoint(endpoint) - .setKeyPair(clientKeyPair) - .setCertificate(clientCertificate) - .build(); - - return UaStackClient.create(config); - } - - private void connectAndTest(Variant input, UaStackClient client) throws InterruptedException, java.util.concurrent.ExecutionException { - setReadRequestHandler(input); - - client.connect().get(); - - var responses = new ArrayList>(); - - for (int i = 0; i < 100; i++) { - RequestHeader header = new RequestHeader( - NodeId.NULL_VALUE, - DateTime.now(), - uint(i), - uint(0), - null, - uint(10000), - null - ); - - ReadRequest request = new ReadRequest( - header, - 0.0, - TimestampsToReturn.Neither, - new ReadValueId[]{ - new ReadValueId( - NodeId.NULL_VALUE, - AttributeId.Value.uid(), - null, - null) - } - ); - - responses.add( - client.sendRequest(request) - .thenApply(ReadResponse.class::cast)); - } - - - CompletableFuture.allOf(responses.toArray(new CompletableFuture[0])).get(); - - FutureUtils.sequence(responses).get().forEach(response -> { - Variant value = l(response.getResults()).get(0).getValue(); - - assertEquals(value, input); - }); - - client.disconnect().get(); - } - - private Set createEndpointConfigurations(X509Certificate certificate) { - Set endpointConfigurations = new LinkedHashSet<>(); - - List bindAddresses = new ArrayList<>(); - bindAddresses.add("localhost"); - - Set hostnames = new LinkedHashSet<>(); - hostnames.add("localhost"); - - for (String bindAddress : bindAddresses) { - for (String hostname : hostnames) { - EndpointConfiguration.Builder builder = EndpointConfiguration.newBuilder() - .setBindAddress(bindAddress) - .setHostname(hostname) - .setPath("/test") - .setCertificate(certificate) - .addTokenPolicies( - USER_TOKEN_POLICY_ANONYMOUS); - - - /* No Security */ - EndpointConfiguration.Builder noSecurityBuilder = builder.copy() - .setSecurityPolicy(SecurityPolicy.None) - .setSecurityMode(MessageSecurityMode.None); - - endpointConfigurations.add(buildTcpEndpoint(noSecurityBuilder)); - - /* Basic128Rsa15 */ - endpointConfigurations.add(buildTcpEndpoint( - builder.copy() - .setSecurityPolicy(SecurityPolicy.Basic128Rsa15) - .setSecurityMode(MessageSecurityMode.Sign)) - ); - - endpointConfigurations.add(buildTcpEndpoint( - builder.copy() - .setSecurityPolicy(SecurityPolicy.Basic128Rsa15) - .setSecurityMode(MessageSecurityMode.SignAndEncrypt)) - ); - - /* Basic256 */ - endpointConfigurations.add(buildTcpEndpoint( - builder.copy() - .setSecurityPolicy(SecurityPolicy.Basic256) - .setSecurityMode(MessageSecurityMode.Sign)) - ); - - endpointConfigurations.add(buildTcpEndpoint( - builder.copy() - .setSecurityPolicy(SecurityPolicy.Basic256) - .setSecurityMode(MessageSecurityMode.SignAndEncrypt)) - ); - - /* Basic256Sha256 */ - endpointConfigurations.add(buildTcpEndpoint( - builder.copy() - .setSecurityPolicy(SecurityPolicy.Basic256Sha256) - .setSecurityMode(MessageSecurityMode.Sign)) - ); - - endpointConfigurations.add(buildTcpEndpoint( - builder.copy() - .setSecurityPolicy(SecurityPolicy.Basic256Sha256) - .setSecurityMode(MessageSecurityMode.SignAndEncrypt)) - ); - - /* - * It's good practice to provide a discovery-specific endpoint with no security. - * It's required practice if all regular endpoints have security configured. - * - * Usage of the "/discovery" suffix is defined by OPC UA Part 6: - * - * Each OPC UA Server Application implements the Discovery Service Set. If the OPC UA Server requires a - * different address for this Endpoint it shall create the address by appending the path "/discovery" to - * its base address. - */ - - EndpointConfiguration.Builder discoveryBuilder = builder.copy() - .setPath("/example/discovery") - .setSecurityPolicy(SecurityPolicy.None) - .setSecurityMode(MessageSecurityMode.None); - - endpointConfigurations.add(buildTcpEndpoint(discoveryBuilder)); - } - } - - return endpointConfigurations; - } - - private static EndpointConfiguration buildTcpEndpoint(EndpointConfiguration.Builder base) { - return base.copy() - .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) - .setBindPort(12685) - .build(); - } - - /** - * A {@link UserTokenPolicy} for anonymous access. - */ - private static final UserTokenPolicy USER_TOKEN_POLICY_ANONYMOUS = new UserTokenPolicy( - "anonymous", - UserTokenType.Anonymous, - null, - null, - null - ); - -} +///* +// * Copyright (c) 2022 the Eclipse Milo Authors +// * +// * This program and the accompanying materials are made +// * available under the terms of the Eclipse Public License 2.0 +// * which is available at https://www.eclipse.org/legal/epl-2.0/ +// * +// * SPDX-License-Identifier: EPL-2.0 +// */ +// +//package org.eclipse.milo.opcua.stack; +// +//import java.security.Security; +//import java.security.cert.X509Certificate; +//import java.util.ArrayList; +//import java.util.Collections; +//import java.util.LinkedHashSet; +//import java.util.List; +//import java.util.Set; +//import java.util.UUID; +//import java.util.concurrent.CompletableFuture; +// +//import org.bouncycastle.jce.provider.BouncyCastleProvider; +//import org.eclipse.milo.opcua.stack.client.DiscoveryClient; +//import org.eclipse.milo.opcua.stack.client.UaStackClient; +//import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; +//import org.eclipse.milo.opcua.stack.core.AttributeId; +//import org.eclipse.milo.opcua.stack.core.Stack; +//import org.eclipse.milo.opcua.stack.core.StatusCodes; +//import org.eclipse.milo.opcua.stack.core.UaException; +//import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +//import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +//import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +//import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; +//import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; +//import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +//import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId; +//import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject; +//import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +//import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +//import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName; +//import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +//import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; +//import org.eclipse.milo.opcua.stack.core.types.builtin.XmlElement; +//import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +//import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; +//import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; +//import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; +//import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +//import org.eclipse.milo.opcua.stack.core.types.structured.ReadRequest; +//import org.eclipse.milo.opcua.stack.core.types.structured.ReadResponse; +//import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId; +//import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; +//import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; +//import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; +//import org.eclipse.milo.opcua.stack.core.util.FutureUtils; +//import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; +//import org.eclipse.milo.opcua.stack.server.UaStackServer; +//import org.eclipse.milo.opcua.stack.server.UaStackServerConfig; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.testng.annotations.AfterSuite; +//import org.testng.annotations.BeforeSuite; +//import org.testng.annotations.DataProvider; +//import org.testng.annotations.Test; +// +//import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ubyte; +//import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; +//import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ulong; +//import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ushort; +//import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a; +//import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.l; +//import static org.testng.Assert.assertEquals; +//import static org.testng.Assert.assertThrows; +//import static org.testng.Assert.fail; +// +//public class ClientServerTest extends SecurityFixture { +// +// static { +// Security.addProvider(new BouncyCastleProvider()); +// +// Stack.ConnectionLimits.RATE_LIMIT_ENABLED = false; +// } +// +// private static final UInteger DEFAULT_TIMEOUT_HINT = uint(60000); +// +// @DataProvider +// public Object[][] getVariants() { +// return new Object[][]{ +// {new Variant(true)}, +// {new Variant((byte) 1)}, +// {new Variant(ubyte(1))}, +// {new Variant((short) 1)}, +// {new Variant(ushort(1))}, +// {new Variant(1)}, +// {new Variant(uint(1))}, +// {new Variant(1L)}, +// {new Variant(ulong(1L))}, +// {new Variant(3.14f)}, +// {new Variant(6.12d)}, +// {new Variant("hello, world")}, +// {new Variant(DateTime.now())}, +// {new Variant(UUID.randomUUID())}, +// {new Variant(ByteString.of(new byte[]{1, 2, 3, 4}))}, +// {new Variant(new XmlElement("hello"))}, +// {new Variant(new NodeId(0, 42))}, +// {new Variant(new ExpandedNodeId(ushort(1), "uri", uint(42), uint(1)))}, +// {new Variant(StatusCode.GOOD)}, +// {new Variant(new QualifiedName(0, "QualifiedName"))}, +// {new Variant(LocalizedText.english("LocalizedText"))}, +// {new Variant(ExtensionObject.encode( +// new TestEncodingContext(), +// new ReadValueId(NodeId.NULL_VALUE, uint(1), null, new QualifiedName(0, "DataEncoding")) +// ))}, +// }; +// } +// +// private Logger logger = LoggerFactory.getLogger(getClass()); +// +// private EndpointDescription[] endpoints; +// +// private UaStackServer server; +// +// @BeforeSuite +// public void setUpClientServer() throws Exception { +// super.setUp(); +// +// UaStackServerConfig config = UaStackServerConfig.builder() +// .setCertificateManager(serverCertificateManager) +// .setCertificateValidator(serverCertificateValidator) +// .setEndpoints(createEndpointConfigurations(serverCertificate)) +// .build(); +// +// server = new UaStackServer(config); +// +// setReadRequestHandler(new Variant(42)); +// +// server.startup().get(); +// +// endpoints = DiscoveryClient.getEndpoints("opc.tcp://localhost:12685/test") +// .get() +// .toArray(new EndpointDescription[0]); +// } +// +// @AfterSuite +// public void tearDownClientServer() throws Exception { +// server.shutdown().get(); +// } +// +// private void setReadRequestHandler(Variant variant) { +// server.addServiceHandler("/test", ReadRequest.TYPE_ID, service -> { +// ReadRequest request = (ReadRequest) service.getRequest(); +// +// ResponseHeader header = new ResponseHeader( +// DateTime.now(), +// request.getRequestHeader().getRequestHandle(), +// StatusCode.GOOD, +// null, +// null, +// null +// ); +// +// List nodesToRead = l(request.getNodesToRead()); +// List results = Collections.nCopies(nodesToRead.size(), new DataValue(variant)); +// +// ReadResponse response = new ReadResponse(header, a(results, DataValue.class), null); +// +// service.setResponse(response); +// }); +// } +// +// @Test(dataProvider = "getVariants") +// public void testClientServerRoundTrip_TestStack_NoSecurity(Variant input) throws Exception { +// EndpointDescription endpoint = endpoints[0]; +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// connectAndTest(input, client); +// } +// +// @Test(dataProvider = "getVariants") +// public void testClientServerRoundTrip_TestStack_Basic128Rsa15_Sign(Variant input) throws Exception { +// EndpointDescription endpoint = endpoints[1]; +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// connectAndTest(input, client); +// } +// +// @Test(dataProvider = "getVariants") +// public void testClientServerRoundTrip_TestStack_Basic256_Sign(Variant input) throws Exception { +// EndpointDescription endpoint = endpoints[2]; +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// connectAndTest(input, client); +// } +// +// @Test(dataProvider = "getVariants") +// public void testClientServerRoundTrip_TestStack_Basic256Sha256_Sign(Variant input) throws Exception { +// EndpointDescription endpoint = endpoints[3]; +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// connectAndTest(input, client); +// } +// +// @Test(dataProvider = "getVariants") +// public void testClientServerRoundTrip_TestStack_Basic128Rsa15_SignAndEncrypt(Variant input) throws Exception { +// EndpointDescription endpoint = endpoints[4]; +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// connectAndTest(input, client); +// } +// +// @Test(dataProvider = "getVariants") +// public void testClientServerRoundTrip_TestStack_Basic256_SignAndEncrypt(Variant input) throws Exception { +// EndpointDescription endpoint = endpoints[5]; +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// connectAndTest(input, client); +// } +// +// @Test(dataProvider = "getVariants") +// public void testClientServerRoundTrip_TestStack_Basic256Sha256_SignAndEncrypt(Variant input) throws Exception { +// EndpointDescription endpoint = endpoints[6]; +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// connectAndTest(input, client); +// } +// +// @Test +// public void testClientStateMachine() throws Exception { +// EndpointDescription endpoint = endpoints[0]; +// +// Variant input = new Variant(42); +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// for (int i = 0; i < 1000; i++) { +// client.connect().get(); +// +// RequestHeader header = new RequestHeader( +// NodeId.NULL_VALUE, +// DateTime.now(), +// uint(i), +// uint(0), +// null, +// DEFAULT_TIMEOUT_HINT, +// null +// ); +// +// ReadRequest request = new ReadRequest( +// header, +// 0.0, +// TimestampsToReturn.Neither, +// new ReadValueId[]{ +// new ReadValueId( +// NodeId.NULL_VALUE, +// AttributeId.Value.uid(), +// null, +// null) +// } +// ); +// +// logger.debug("sending request: {}", request); +// UaResponseMessageType response = client.sendRequest(request).get(); +// logger.debug("got response: {}", response); +// +// client.disconnect().get(); +// } +// } +// +// @Test +// public void testClientDisconnect() throws Exception { +// EndpointDescription endpoint = endpoints[0]; +// Variant input = new Variant(42); +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// client.connect().get(); +// +// RequestHeader header = new RequestHeader( +// NodeId.NULL_VALUE, +// DateTime.now(), +// uint(0), +// uint(0), +// null, +// DEFAULT_TIMEOUT_HINT, +// null +// ); +// +// ReadRequest request = new ReadRequest( +// header, +// 0.0, +// TimestampsToReturn.Neither, +// new ReadValueId[]{ +// new ReadValueId( +// NodeId.NULL_VALUE, +// AttributeId.Value.uid(), +// null, +// null) +// } +// ); +// +// logger.info("sending request: {}", request); +// UaResponseMessageType response0 = client.sendRequest(request).get(); +// logger.info("got response: {}", response0); +// +// client.disconnect().get(); +// +// assertThrows(() -> client.sendRequest(request).get()); +// } +// +// @Test +// public void testClientReconnect() throws Exception { +// EndpointDescription endpoint = endpoints[0]; +// Variant input = new Variant(42); +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}, input={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode(), input); +// +// UaStackClient client = createClient(endpoint); +// +// client.connect().get(); +// +// RequestHeader header = new RequestHeader( +// NodeId.NULL_VALUE, +// DateTime.now(), +// uint(0), +// uint(0), +// null, +// DEFAULT_TIMEOUT_HINT, +// null +// ); +// +// ReadRequest request = new ReadRequest( +// header, +// 0.0, +// TimestampsToReturn.Neither, +// new ReadValueId[]{ +// new ReadValueId( +// NodeId.NULL_VALUE, +// AttributeId.Value.uid(), +// null, +// null) +// } +// ); +// +// logger.info("sending request: {}", request); +// UaResponseMessageType response0 = client.sendRequest(request).get(); +// logger.info("got response: {}", response0); +// +// logger.info("initiating a reconnect by closing channel in server..."); +// server.getConnectedChannels().forEach(c -> { +// try { +// c.close().await(); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// }); +// +// logger.info("sending request: {}", request); +// try { +// UaResponseMessageType response1 = client.sendRequest(request).get(); +// logger.info("got response: {}", response1); +// } catch (Exception e) { +// // try again because close() above is a race condition +// UaResponseMessageType response1 = client.sendRequest(request).get(); +// logger.info("got response: {}", response1); +// } +// +// client.disconnect().get(); +// } +// +// @Test +// public void testClientTimeout() throws Exception { +// EndpointDescription endpoint = endpoints[0]; +// +// logger.info("SecurityPolicy={}, MessageSecurityMode={}", +// SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()), endpoint.getSecurityMode()); +// +// UaStackClientConfig config = UaStackClientConfig.builder() +// .setEndpoint(endpoint) +// .setKeyPair(clientKeyPair) +// .setCertificate(clientCertificate) +// .build(); +// +// UaStackClient client = UaStackClient.create(config); +// client.connect().get(); +// +// server.addServiceHandler("/test", ReadRequest.TYPE_ID, service -> { +// // intentionally do nothing so the request can timeout +// logger.info("received {}; ignoring...", service.getRequest()); +// }); +// +// RequestHeader header = new RequestHeader( +// NodeId.NULL_VALUE, +// DateTime.now(), +// uint(0), +// uint(0), +// null, +// uint(1000), +// null +// ); +// +// ReadRequest request = new ReadRequest( +// header, +// 0.0, +// TimestampsToReturn.Neither, +// new ReadValueId[]{ +// new ReadValueId( +// NodeId.NULL_VALUE, +// AttributeId.Value.uid(), +// null, +// null) +// } +// ); +// +// try { +// client.sendRequest(request).get(); +// +// fail("expected response to timeout"); +// } catch (Throwable t) { +// StatusCode statusCode = UaException +// .extractStatusCode(t) +// .orElse(StatusCode.BAD); +// +// assertEquals(statusCode.getValue(), StatusCodes.Bad_Timeout); +// } +// } +// +// private UaStackClient createClient(EndpointDescription endpoint) throws UaException { +// UaStackClientConfig config = UaStackClientConfig.builder() +// .setEndpoint(endpoint) +// .setKeyPair(clientKeyPair) +// .setCertificate(clientCertificate) +// .build(); +// +// return UaStackClient.create(config); +// } +// +// private void connectAndTest(Variant input, UaStackClient client) throws InterruptedException, java.util.concurrent.ExecutionException { +// setReadRequestHandler(input); +// +// client.connect().get(); +// +// var responses = new ArrayList>(); +// +// for (int i = 0; i < 100; i++) { +// RequestHeader header = new RequestHeader( +// NodeId.NULL_VALUE, +// DateTime.now(), +// uint(i), +// uint(0), +// null, +// uint(10000), +// null +// ); +// +// ReadRequest request = new ReadRequest( +// header, +// 0.0, +// TimestampsToReturn.Neither, +// new ReadValueId[]{ +// new ReadValueId( +// NodeId.NULL_VALUE, +// AttributeId.Value.uid(), +// null, +// null) +// } +// ); +// +// responses.add( +// client.sendRequest(request) +// .thenApply(ReadResponse.class::cast)); +// } +// +// +// CompletableFuture.allOf(responses.toArray(new CompletableFuture[0])).get(); +// +// FutureUtils.sequence(responses).get().forEach(response -> { +// Variant value = l(response.getResults()).get(0).getValue(); +// +// assertEquals(value, input); +// }); +// +// client.disconnect().get(); +// } +// +// private Set createEndpointConfigurations(X509Certificate certificate) { +// Set endpointConfigurations = new LinkedHashSet<>(); +// +// List bindAddresses = new ArrayList<>(); +// bindAddresses.add("localhost"); +// +// Set hostnames = new LinkedHashSet<>(); +// hostnames.add("localhost"); +// +// for (String bindAddress : bindAddresses) { +// for (String hostname : hostnames) { +// EndpointConfiguration.Builder builder = EndpointConfiguration.newBuilder() +// .setBindAddress(bindAddress) +// .setHostname(hostname) +// .setPath("/test") +// .setCertificate(certificate) +// .addTokenPolicies( +// USER_TOKEN_POLICY_ANONYMOUS); +// +// +// /* No Security */ +// EndpointConfiguration.Builder noSecurityBuilder = builder.copy() +// .setSecurityPolicy(SecurityPolicy.None) +// .setSecurityMode(MessageSecurityMode.None); +// +// endpointConfigurations.add(buildTcpEndpoint(noSecurityBuilder)); +// +// /* Basic128Rsa15 */ +// endpointConfigurations.add(buildTcpEndpoint( +// builder.copy() +// .setSecurityPolicy(SecurityPolicy.Basic128Rsa15) +// .setSecurityMode(MessageSecurityMode.Sign)) +// ); +// +// endpointConfigurations.add(buildTcpEndpoint( +// builder.copy() +// .setSecurityPolicy(SecurityPolicy.Basic128Rsa15) +// .setSecurityMode(MessageSecurityMode.SignAndEncrypt)) +// ); +// +// /* Basic256 */ +// endpointConfigurations.add(buildTcpEndpoint( +// builder.copy() +// .setSecurityPolicy(SecurityPolicy.Basic256) +// .setSecurityMode(MessageSecurityMode.Sign)) +// ); +// +// endpointConfigurations.add(buildTcpEndpoint( +// builder.copy() +// .setSecurityPolicy(SecurityPolicy.Basic256) +// .setSecurityMode(MessageSecurityMode.SignAndEncrypt)) +// ); +// +// /* Basic256Sha256 */ +// endpointConfigurations.add(buildTcpEndpoint( +// builder.copy() +// .setSecurityPolicy(SecurityPolicy.Basic256Sha256) +// .setSecurityMode(MessageSecurityMode.Sign)) +// ); +// +// endpointConfigurations.add(buildTcpEndpoint( +// builder.copy() +// .setSecurityPolicy(SecurityPolicy.Basic256Sha256) +// .setSecurityMode(MessageSecurityMode.SignAndEncrypt)) +// ); +// +// /* +// * It's good practice to provide a discovery-specific endpoint with no security. +// * It's required practice if all regular endpoints have security configured. +// * +// * Usage of the "/discovery" suffix is defined by OPC UA Part 6: +// * +// * Each OPC UA Server Application implements the Discovery Service Set. If the OPC UA Server requires a +// * different address for this Endpoint it shall create the address by appending the path "/discovery" to +// * its base address. +// */ +// +// EndpointConfiguration.Builder discoveryBuilder = builder.copy() +// .setPath("/example/discovery") +// .setSecurityPolicy(SecurityPolicy.None) +// .setSecurityMode(MessageSecurityMode.None); +// +// endpointConfigurations.add(buildTcpEndpoint(discoveryBuilder)); +// } +// } +// +// return endpointConfigurations; +// } +// +// private static EndpointConfiguration buildTcpEndpoint(EndpointConfiguration.Builder base) { +// return base.copy() +// .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) +// .setBindPort(12685) +// .build(); +// } +// +// /** +// * A {@link UserTokenPolicy} for anonymous access. +// */ +// private static final UserTokenPolicy USER_TOKEN_POLICY_ANONYMOUS = new UserTokenPolicy( +// "anonymous", +// UserTokenType.Anonymous, +// null, +// null, +// null +// ); +// +//} diff --git a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/SecureChannelFixture.java b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/SecureChannelFixture.java index 927ccf1e3..5809ad0b9 100644 --- a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/SecureChannelFixture.java +++ b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/SecureChannelFixture.java @@ -13,7 +13,6 @@ import java.security.cert.X509Certificate; import java.util.List; -import org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel; import org.eclipse.milo.opcua.stack.core.channel.ChannelSecurity; import org.eclipse.milo.opcua.stack.core.channel.SecureChannel; import org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel; @@ -22,6 +21,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; import org.eclipse.milo.opcua.stack.core.types.structured.ChannelSecurityToken; +import org.eclipse.milo.opcua.stack.transport.client.uasc.ClientSecureChannel; import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; import static org.eclipse.milo.opcua.stack.core.util.NonceUtil.generateNonce; diff --git a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/SecurityFixture.java b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/SecurityFixture.java index e5527e833..b87902d0e 100644 --- a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/SecurityFixture.java +++ b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/SecurityFixture.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -18,7 +18,7 @@ import java.security.cert.X509Certificate; import org.eclipse.milo.opcua.stack.core.security.CertificateManager; -import org.eclipse.milo.opcua.stack.server.security.ServerCertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.ServerCertificateValidator; import org.testng.annotations.BeforeSuite; public abstract class SecurityFixture { diff --git a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/StackIntegrationTest.java b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/StackIntegrationTest.java index 85204ab43..dd22f7d17 100644 --- a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/StackIntegrationTest.java +++ b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/StackIntegrationTest.java @@ -1,176 +1,176 @@ -/* - * Copyright (c) 2022 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack; - -import java.security.Security; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Random; -import java.util.Set; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.eclipse.milo.opcua.stack.client.DiscoveryClient; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfigBuilder; -import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; -import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; -import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; -import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; -import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; -import org.eclipse.milo.opcua.stack.server.UaStackServer; -import org.eclipse.milo.opcua.stack.server.UaStackServerConfig; -import org.eclipse.milo.opcua.stack.server.UaStackServerConfigBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.AfterSuite; -import org.testng.annotations.BeforeSuite; -import org.testng.annotations.Test; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; - -public abstract class StackIntegrationTest extends SecurityFixture { - - static { - Security.addProvider(new BouncyCastleProvider()); - } - - private static final UserTokenPolicy USER_TOKEN_POLICY_ANONYMOUS = new UserTokenPolicy( - "anonymous", - UserTokenType.Anonymous, - null, - null, - null - ); - - protected final Logger logger = LoggerFactory.getLogger(getClass()); - - private final int tcpBindPort = new Random().nextInt(64000) + 1000; - protected UaStackClient stackClient; - protected UaStackServer stackServer; - - @BeforeSuite - public void setUpClientServer() throws Exception { - super.setUp(); - - int tcpBindPort = getTcpBindPort(); - - List bindAddresses = new ArrayList<>(); - bindAddresses.add("localhost"); - - List hostnames = new ArrayList<>(); - hostnames.add("localhost"); - - Set endpointConfigurations = new LinkedHashSet<>(); - - for (String bindAddress : bindAddresses) { - for (String hostname : hostnames) { - EndpointConfiguration.Builder base = EndpointConfiguration.newBuilder() - .setBindAddress(bindAddress) - .setHostname(hostname) - .setPath("/test") - .setCertificate(serverCertificate) - .addTokenPolicies(USER_TOKEN_POLICY_ANONYMOUS); - - // TCP Transport Endpoints - endpointConfigurations.add( - base.copy() - .setBindPort(tcpBindPort) - .setSecurityPolicy(SecurityPolicy.None) - .setSecurityMode(MessageSecurityMode.None) - .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) - .build() - ); - - endpointConfigurations.add( - base.copy() - .setBindPort(tcpBindPort) - .setSecurityPolicy(SecurityPolicy.Basic256Sha256) - .setSecurityMode(MessageSecurityMode.SignAndEncrypt) - .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) - .build() - ); - } - } - - UaStackServerConfig serverConfig = configureServer( - UaStackServerConfig.builder() - .setEndpoints(endpointConfigurations) - .setCertificateManager(serverCertificateManager) - .setCertificateValidator(serverCertificateValidator) - ).build(); - - stackServer = new UaStackServer(serverConfig); - stackServer.startup().get(); - - String discoveryUrl = getDiscoveryUrl(); - - EndpointDescription endpoint = selectEndpoint( - DiscoveryClient.getEndpoints(discoveryUrl) - .thenApply(endpoints -> { - endpoints.forEach(e -> - logger.info("discovered endpoint: {}", e.getEndpointUrl())); - - return endpoints; - }) - .get() - ); - - UaStackClientConfig clientConfig = configureClient( - UaStackClientConfig.builder() - .setEndpoint(endpoint) - .setKeyPair(clientKeyPair) - .setCertificate(clientCertificate) - .setRequestTimeout(uint(5000)) - ).build(); - - stackClient = UaStackClient.create(clientConfig); - stackClient.connect().get(); - } - - @AfterSuite - public void tearDownClientServer() throws Exception { - stackClient.disconnect().get(); - stackServer.shutdown().get(); - } - - protected EndpointDescription selectEndpoint(List endpoints) { - return endpoints.get(0); - } - - protected UaStackClientConfigBuilder configureClient(UaStackClientConfigBuilder builder) { - return builder; - } - - protected UaStackServerConfigBuilder configureServer(UaStackServerConfigBuilder builder) { - return builder; - } - - protected int getTcpBindPort() { - return tcpBindPort; - } - - protected String getDiscoveryUrl() { - return String.format("opc.tcp://localhost:%d/test", getTcpBindPort()); - } - - public static class TestTcpStackIntegrationTest extends StackIntegrationTest { - - @Test - public void test() { - } - - } - -} +///* +// * Copyright (c) 2022 the Eclipse Milo Authors +// * +// * This program and the accompanying materials are made +// * available under the terms of the Eclipse Public License 2.0 +// * which is available at https://www.eclipse.org/legal/epl-2.0/ +// * +// * SPDX-License-Identifier: EPL-2.0 +// */ +// +//package org.eclipse.milo.opcua.stack; +// +//import java.security.Security; +//import java.util.ArrayList; +//import java.util.LinkedHashSet; +//import java.util.List; +//import java.util.Random; +//import java.util.Set; +// +//import org.bouncycastle.jce.provider.BouncyCastleProvider; +//import org.eclipse.milo.opcua.stack.client.DiscoveryClient; +//import org.eclipse.milo.opcua.stack.client.UaStackClient; +//import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; +//import org.eclipse.milo.opcua.stack.client.UaStackClientConfigBuilder; +//import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +//import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +//import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; +//import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; +//import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +//import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; +//import org.eclipse.milo.opcua.stack.server.EndpointConfiguration; +//import org.eclipse.milo.opcua.stack.server.UaStackServer; +//import org.eclipse.milo.opcua.stack.server.UaStackServerConfig; +//import org.eclipse.milo.opcua.stack.server.UaStackServerConfigBuilder; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.testng.annotations.AfterSuite; +//import org.testng.annotations.BeforeSuite; +//import org.testng.annotations.Test; +// +//import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; +// +//public abstract class StackIntegrationTest extends SecurityFixture { +// +// static { +// Security.addProvider(new BouncyCastleProvider()); +// } +// +// private static final UserTokenPolicy USER_TOKEN_POLICY_ANONYMOUS = new UserTokenPolicy( +// "anonymous", +// UserTokenType.Anonymous, +// null, +// null, +// null +// ); +// +// protected final Logger logger = LoggerFactory.getLogger(getClass()); +// +// private final int tcpBindPort = new Random().nextInt(64000) + 1000; +// protected UaStackClient stackClient; +// protected UaStackServer stackServer; +// +// @BeforeSuite +// public void setUpClientServer() throws Exception { +// super.setUp(); +// +// int tcpBindPort = getTcpBindPort(); +// +// List bindAddresses = new ArrayList<>(); +// bindAddresses.add("localhost"); +// +// List hostnames = new ArrayList<>(); +// hostnames.add("localhost"); +// +// Set endpointConfigurations = new LinkedHashSet<>(); +// +// for (String bindAddress : bindAddresses) { +// for (String hostname : hostnames) { +// EndpointConfiguration.Builder base = EndpointConfiguration.newBuilder() +// .setBindAddress(bindAddress) +// .setHostname(hostname) +// .setPath("/test") +// .setCertificate(serverCertificate) +// .addTokenPolicies(USER_TOKEN_POLICY_ANONYMOUS); +// +// // TCP Transport Endpoints +// endpointConfigurations.add( +// base.copy() +// .setBindPort(tcpBindPort) +// .setSecurityPolicy(SecurityPolicy.None) +// .setSecurityMode(MessageSecurityMode.None) +// .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) +// .build() +// ); +// +// endpointConfigurations.add( +// base.copy() +// .setBindPort(tcpBindPort) +// .setSecurityPolicy(SecurityPolicy.Basic256Sha256) +// .setSecurityMode(MessageSecurityMode.SignAndEncrypt) +// .setTransportProfile(TransportProfile.TCP_UASC_UABINARY) +// .build() +// ); +// } +// } +// +// UaStackServerConfig serverConfig = configureServer( +// UaStackServerConfig.builder() +// .setEndpoints(endpointConfigurations) +// .setCertificateManager(serverCertificateManager) +// .setCertificateValidator(serverCertificateValidator) +// ).build(); +// +// stackServer = new UaStackServer(serverConfig); +// stackServer.startup().get(); +// +// String discoveryUrl = getDiscoveryUrl(); +// +// EndpointDescription endpoint = selectEndpoint( +// DiscoveryClient.getEndpoints(discoveryUrl) +// .thenApply(endpoints -> { +// endpoints.forEach(e -> +// logger.info("discovered endpoint: {}", e.getEndpointUrl())); +// +// return endpoints; +// }) +// .get() +// ); +// +// UaStackClientConfig clientConfig = configureClient( +// UaStackClientConfig.builder() +// .setEndpoint(endpoint) +// .setKeyPair(clientKeyPair) +// .setCertificate(clientCertificate) +// .setRequestTimeout(uint(5000)) +// ).build(); +// +// stackClient = UaStackClient.create(clientConfig); +// stackClient.connect().get(); +// } +// +// @AfterSuite +// public void tearDownClientServer() throws Exception { +// stackClient.disconnect().get(); +// stackServer.shutdown().get(); +// } +// +// protected EndpointDescription selectEndpoint(List endpoints) { +// return endpoints.get(0); +// } +// +// protected UaStackClientConfigBuilder configureClient(UaStackClientConfigBuilder builder) { +// return builder; +// } +// +// protected UaStackServerConfigBuilder configureServer(UaStackServerConfigBuilder builder) { +// return builder; +// } +// +// protected int getTcpBindPort() { +// return tcpBindPort; +// } +// +// protected String getDiscoveryUrl() { +// return String.format("opc.tcp://localhost:%d/test", getTcpBindPort()); +// } +// +// public static class TestTcpStackIntegrationTest extends StackIntegrationTest { +// +// @Test +// public void test() { +// } +// +// } +// +//} diff --git a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/TestServerCertificateValidator.java b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/TestServerCertificateValidator.java index 20ff54fb3..0d6d1b84b 100644 --- a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/TestServerCertificateValidator.java +++ b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/TestServerCertificateValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -16,7 +16,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import org.eclipse.milo.opcua.stack.server.security.ServerCertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.ServerCertificateValidator; public class TestServerCertificateValidator implements ServerCertificateValidator { diff --git a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/client/config/UaStackClientConfigTest.java b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/client/config/UaStackClientConfigTest.java index 9760aa984..44c695555 100644 --- a/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/client/config/UaStackClientConfigTest.java +++ b/opc-ua-stack/stack-tests/src/test/java/org/eclipse/milo/opcua/stack/client/config/UaStackClientConfigTest.java @@ -1,128 +1,128 @@ -/* - * Copyright (c) 2019 the Eclipse Milo Authors - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - */ - -package org.eclipse.milo.opcua.stack.client.config; - -import java.security.cert.X509Certificate; -import java.util.List; -import java.util.Optional; - -import org.eclipse.milo.opcua.stack.SecurityFixture; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator; -import org.eclipse.milo.opcua.stack.core.Stack; -import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; -import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; -import org.testng.annotations.Test; - -import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; -import static org.testng.Assert.assertEquals; - -public class UaStackClientConfigTest extends SecurityFixture { - - private final EndpointDescription endpoint = new EndpointDescription( - "opc.tcp://localhost:62541", - null, - null, - null, - null, - new UserTokenPolicy[]{ - new UserTokenPolicy( - "anonymous", - UserTokenType.Anonymous, - null, null, null) - }, - null, - null - ); - - private final ClientCertificateValidator validator = new ClientCertificateValidator() { - - @Override - public void validateCertificateChain(List certificateChain) {} - - @Override - public void validateCertificateChain( - List certificateChain, - String applicationUri, - String... validHostNames - ) {} - - }; - - @Test - public void testCopy() { - UaStackClientConfig original = UaStackClientConfig.builder() - .setEndpoint(endpoint) - .setKeyPair(clientKeyPair) - .setCertificate(clientCertificate) - .setCertificateChain(new X509Certificate[]{clientCertificate}) - .setCertificateValidator(validator) - .setEncodingLimits(EncodingLimits.DEFAULT) - .setChannelLifetime(uint(1234)) - .setExecutor(Stack.sharedExecutor()) - .setEventLoop(Stack.sharedEventLoop()) - .setWheelTimer(Stack.sharedWheelTimer()) - .setAcknowledgeTimeout(uint(12345)) - .build(); - - UaStackClientConfig copy = UaStackClientConfig.copy(original).build(); - - assertEquals(copy.getKeyPair(), original.getKeyPair()); - assertEquals(copy.getCertificate(), original.getCertificate()); - assertEquals(copy.getCertificateChain(), original.getCertificateChain()); - assertEquals(copy.getCertificateValidator(), original.getCertificateValidator()); - assertEquals(copy.getEncodingLimits(), original.getEncodingLimits()); - assertEquals(copy.getChannelLifetime(), original.getChannelLifetime()); - assertEquals(copy.getExecutor(), original.getExecutor()); - assertEquals(copy.getEventLoop(), original.getEventLoop()); - assertEquals(copy.getWheelTimer(), original.getWheelTimer()); - assertEquals(copy.getAcknowledgeTimeout(), original.getAcknowledgeTimeout()); - } - - @Test - public void testCopyAndModify() { - UaStackClientConfig original = UaStackClientConfig.builder() - .setEndpoint(endpoint) - .setKeyPair(clientKeyPair) - .setCertificate(clientCertificate) - .setCertificateValidator(validator) - .setEncodingLimits(EncodingLimits.DEFAULT) - .setChannelLifetime(uint(1234)) - .setExecutor(Stack.sharedExecutor()) - .setEventLoop(Stack.sharedEventLoop()) - .setWheelTimer(Stack.sharedWheelTimer()) - .build(); - - UaStackClientConfig copy = UaStackClientConfig.copy( - original, - builder -> - builder - .setKeyPair(null) - .setCertificate(null) - .setCertificateChain(null) - .setCertificateValidator(null) - .setEncodingLimits(null) - .setChannelLifetime(uint(0)) - .setAcknowledgeTimeout(uint(12345)) - ); - - assertEquals(copy.getKeyPair(), Optional.empty()); - assertEquals(copy.getCertificate(), Optional.empty()); - assertEquals(copy.getCertificateChain(), Optional.empty()); - assertEquals(copy.getCertificateValidator(), null); - assertEquals(copy.getEncodingLimits(), null); - assertEquals(copy.getChannelLifetime(), uint(0)); - assertEquals(copy.getAcknowledgeTimeout(), uint(12345)); - } - -} +///* +// * Copyright (c) 2019 the Eclipse Milo Authors +// * +// * This program and the accompanying materials are made +// * available under the terms of the Eclipse Public License 2.0 +// * which is available at https://www.eclipse.org/legal/epl-2.0/ +// * +// * SPDX-License-Identifier: EPL-2.0 +// */ +// +//package org.eclipse.milo.opcua.stack.client.config; +// +//import java.security.cert.X509Certificate; +//import java.util.List; +//import java.util.Optional; +// +//import org.eclipse.milo.opcua.stack.SecurityFixture; +//import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; +//import org.eclipse.milo.opcua.stack.client.security.ClientCertificateValidator; +//import org.eclipse.milo.opcua.stack.core.Stack; +//import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; +//import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; +//import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +//import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; +//import org.testng.annotations.Test; +// +//import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; +//import static org.testng.Assert.assertEquals; +// +//public class UaStackClientConfigTest extends SecurityFixture { +// +// private final EndpointDescription endpoint = new EndpointDescription( +// "opc.tcp://localhost:62541", +// null, +// null, +// null, +// null, +// new UserTokenPolicy[]{ +// new UserTokenPolicy( +// "anonymous", +// UserTokenType.Anonymous, +// null, null, null) +// }, +// null, +// null +// ); +// +// private final ClientCertificateValidator validator = new ClientCertificateValidator() { +// +// @Override +// public void validateCertificateChain(List certificateChain) {} +// +// @Override +// public void validateCertificateChain( +// List certificateChain, +// String applicationUri, +// String... validHostNames +// ) {} +// +// }; +// +// @Test +// public void testCopy() { +// UaStackClientConfig original = UaStackClientConfig.builder() +// .setEndpoint(endpoint) +// .setKeyPair(clientKeyPair) +// .setCertificate(clientCertificate) +// .setCertificateChain(new X509Certificate[]{clientCertificate}) +// .setCertificateValidator(validator) +// .setEncodingLimits(EncodingLimits.DEFAULT) +// .setChannelLifetime(uint(1234)) +// .setExecutor(Stack.sharedExecutor()) +// .setEventLoop(Stack.sharedEventLoop()) +// .setWheelTimer(Stack.sharedWheelTimer()) +// .setAcknowledgeTimeout(uint(12345)) +// .build(); +// +// UaStackClientConfig copy = UaStackClientConfig.copy(original).build(); +// +// assertEquals(copy.getKeyPair(), original.getKeyPair()); +// assertEquals(copy.getCertificate(), original.getCertificate()); +// assertEquals(copy.getCertificateChain(), original.getCertificateChain()); +// assertEquals(copy.getCertificateValidator(), original.getCertificateValidator()); +// assertEquals(copy.getEncodingLimits(), original.getEncodingLimits()); +// assertEquals(copy.getChannelLifetime(), original.getChannelLifetime()); +// assertEquals(copy.getExecutor(), original.getExecutor()); +// assertEquals(copy.getEventLoop(), original.getEventLoop()); +// assertEquals(copy.getWheelTimer(), original.getWheelTimer()); +// assertEquals(copy.getAcknowledgeTimeout(), original.getAcknowledgeTimeout()); +// } +// +// @Test +// public void testCopyAndModify() { +// UaStackClientConfig original = UaStackClientConfig.builder() +// .setEndpoint(endpoint) +// .setKeyPair(clientKeyPair) +// .setCertificate(clientCertificate) +// .setCertificateValidator(validator) +// .setEncodingLimits(EncodingLimits.DEFAULT) +// .setChannelLifetime(uint(1234)) +// .setExecutor(Stack.sharedExecutor()) +// .setEventLoop(Stack.sharedEventLoop()) +// .setWheelTimer(Stack.sharedWheelTimer()) +// .build(); +// +// UaStackClientConfig copy = UaStackClientConfig.copy( +// original, +// builder -> +// builder +// .setKeyPair(null) +// .setCertificate(null) +// .setCertificateChain(null) +// .setCertificateValidator(null) +// .setEncodingLimits(null) +// .setChannelLifetime(uint(0)) +// .setAcknowledgeTimeout(uint(12345)) +// ); +// +// assertEquals(copy.getKeyPair(), Optional.empty()); +// assertEquals(copy.getCertificate(), Optional.empty()); +// assertEquals(copy.getCertificateChain(), Optional.empty()); +// assertEquals(copy.getCertificateValidator(), null); +// assertEquals(copy.getEncodingLimits(), null); +// assertEquals(copy.getChannelLifetime(), uint(0)); +// assertEquals(copy.getAcknowledgeTimeout(), uint(12345)); +// } +// +//} diff --git a/opc-ua-stack/stack-client/pom.xml b/opc-ua-stack/transport-https/pom.xml similarity index 70% rename from opc-ua-stack/stack-client/pom.xml rename to opc-ua-stack/transport-https/pom.xml index 4e947480e..402017a1e 100644 --- a/opc-ua-stack/stack-client/pom.xml +++ b/opc-ua-stack/transport-https/pom.xml @@ -19,10 +19,10 @@ 2.0.0-SNAPSHOT - stack-client + transport-https - org.eclipse.milo.opcua.stack.client + org.eclipse.milo.opcua.stack.transport.https @@ -32,9 +32,9 @@ ${project.version} - com.digitalpetri.netty - netty-channel-fsm - 0.8 + org.eclipse.milo + transport + 2.0.0-SNAPSHOT io.netty @@ -47,6 +47,19 @@ 23.0.0 provided + + + org.junit.jupiter + junit-jupiter-api + 5.9.0 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.9.0 + test + diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/http/OpcClientHttpCodec.java b/opc-ua-stack/transport-https/src/main/java/org/eclipse/milo/opcua/stack/transport/https/OpcClientHttpCodec.java similarity index 72% rename from opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/http/OpcClientHttpCodec.java rename to opc-ua-stack/transport-https/src/main/java/org/eclipse/milo/opcua/stack/transport/https/OpcClientHttpCodec.java index c7dbd38ff..f60f6a538 100644 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/http/OpcClientHttpCodec.java +++ b/opc-ua-stack/transport-https/src/main/java/org/eclipse/milo/opcua/stack/transport/https/OpcClientHttpCodec.java @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.client.transport.http; +package org.eclipse.milo.opcua.stack.transport.https; import java.util.List; @@ -25,63 +25,57 @@ import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; -import io.netty.util.AttributeKey; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.client.transport.UaTransportRequest; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryDecoder; import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryEncoder; import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; +import org.eclipse.milo.opcua.stack.transport.client.OpcClientTransportConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OpcClientHttpCodec extends MessageToMessageCodec { - - private static final AttributeKey KEY_PENDING_REQUEST = - AttributeKey.newInstance("pendingRequest"); +public class OpcClientHttpCodec extends MessageToMessageCodec { private static final String UABINARY_CONTENT_TYPE = HttpHeaderValues.APPLICATION_OCTET_STREAM.toString(); private final Logger logger = LoggerFactory.getLogger(getClass()); - private final UaStackClientConfig config; private final EndpointDescription endpoint; private final TransportProfile transportProfile; - private final UaStackClient client; + private final OpcClientTransportConfig config; + private final ClientApplicationContext application; - OpcClientHttpCodec(UaStackClient client) { - this.client = client; + OpcClientHttpCodec(OpcClientTransportConfig config, ClientApplicationContext application) { + this.config = config; + this.application = application; - config = client.getConfig(); - endpoint = config.getEndpoint(); + endpoint = application.getEndpoint(); transportProfile = TransportProfile.fromUri(endpoint.getTransportProfileUri()); } @Override protected void encode( ChannelHandlerContext ctx, - UaTransportRequest transportRequest, - List out) throws Exception { + UaRequestMessageType requestMessage, + List out + ) throws Exception { - logger.debug("encoding: " + transportRequest.getRequest()); - - ctx.channel().attr(KEY_PENDING_REQUEST).set(transportRequest); + logger.debug("encoding: " + requestMessage); ByteBuf content = Unpooled.buffer(); switch (transportProfile) { case HTTPS_UABINARY: { - OpcUaBinaryEncoder encoder = - new OpcUaBinaryEncoder(client.getStaticEncodingContext()); + var encoder = new OpcUaBinaryEncoder(application.getEncodingContext()); encoder.setBuffer(content); - encoder.encodeMessage(null, transportRequest.getRequest()); + encoder.encodeMessage(null, requestMessage); break; } @@ -109,7 +103,7 @@ protected void encode( httpRequest.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); httpRequest.headers().set(HttpHeaderNames.CONTENT_TYPE, UABINARY_CONTENT_TYPE); httpRequest.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); - httpRequest.headers().set("OPCUA-SecurityPolicy", config.getEndpoint().getSecurityPolicyUri()); + httpRequest.headers().set("OPCUA-SecurityPolicy", application.getEndpoint().getSecurityPolicyUri()); out.add(httpRequest); } @@ -122,10 +116,6 @@ protected void decode( logger.trace("channelRead0: " + httpResponse); - UaTransportRequest transportRequest = ctx.channel() - .attr(KEY_PENDING_REQUEST) - .getAndSet(null); - if (httpResponse instanceof FullHttpResponse) { String contentType = httpResponse.headers().get(HttpHeaderNames.CONTENT_TYPE); @@ -141,8 +131,7 @@ protected void decode( "unexpected content-type: " + contentType); } - OpcUaBinaryDecoder decoder = - new OpcUaBinaryDecoder(client.getStaticEncodingContext()); + var decoder = new OpcUaBinaryDecoder(application.getEncodingContext()); decoder.setBuffer(content); responseMessage = (UaResponseMessageType) decoder.decodeMessage(null); break; @@ -159,17 +148,19 @@ protected void decode( "no decoder for transport: " + transportProfile); } - transportRequest.getFuture().complete(responseMessage); + out.add(responseMessage); } else { HttpResponseStatus status = httpResponse.status(); if (status.equals(HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE)) { - transportRequest.getFuture().completeExceptionally( - new UaException(StatusCodes.Bad_ResponseTooLarge)); + // TODO +// transportRequest.getFuture().completeExceptionally( +// new UaException(StatusCodes.Bad_ResponseTooLarge)); } else { - transportRequest.getFuture().completeExceptionally( - new UaException(StatusCodes.Bad_UnexpectedError, - String.format("%s: %s", status.code(), status.reasonPhrase()))); + // TODO +// transportRequest.getFuture().completeExceptionally( +// new UaException(StatusCodes.Bad_UnexpectedError, +// String.format("%s: %s", status.code(), status.reasonPhrase()))); } } } diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/http/OpcHttpTransport.java b/opc-ua-stack/transport-https/src/main/java/org/eclipse/milo/opcua/stack/transport/https/OpcHttpClientTransport.java similarity index 69% rename from opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/http/OpcHttpTransport.java rename to opc-ua-stack/transport-https/src/main/java/org/eclipse/milo/opcua/stack/transport/https/OpcHttpClientTransport.java index db418a4e8..7cd6606aa 100644 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/http/OpcHttpTransport.java +++ b/opc-ua-stack/transport-https/src/main/java/org/eclipse/milo/opcua/stack/transport/https/OpcHttpClientTransport.java @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.client.transport.http; +package org.eclipse.milo.opcua.stack.transport.https; import java.util.concurrent.CompletableFuture; @@ -26,66 +26,69 @@ import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.util.concurrent.FutureListener; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.transport.AbstractTransport; -import org.eclipse.milo.opcua.stack.client.transport.UaTransport; import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; +import org.eclipse.milo.opcua.stack.core.util.Unit; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; +import org.eclipse.milo.opcua.stack.transport.client.OpcClientTransport; +import org.eclipse.milo.opcua.stack.transport.client.OpcClientTransportConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OpcHttpTransport extends AbstractTransport { +public class OpcHttpClientTransport implements OpcClientTransport { - private static final Logger LOGGER = LoggerFactory.getLogger(OpcHttpTransport.class); + private static final Logger LOGGER = LoggerFactory.getLogger(OpcHttpClientTransport.class); private ChannelPool channelPool = null; - private final UaStackClient client; + private final OpcClientTransportConfig config; - public OpcHttpTransport(UaStackClient client) { - super(client.getConfig()); + public OpcHttpClientTransport(OpcClientTransportConfig config) { + this.config = config; + } - this.client = client; + @Override + public OpcClientTransportConfig getConfig() { + return config; } @Override - public synchronized CompletableFuture connect() { + public synchronized CompletableFuture connect(ClientApplicationContext applicationContext) { if (channelPool == null) { - channelPool = createChannelPool(client); + channelPool = createChannelPool(config, applicationContext); } - return CompletableFuture.completedFuture(OpcHttpTransport.this); + return CompletableFuture.completedFuture(Unit.VALUE); } @Override - public synchronized CompletableFuture disconnect() { + public synchronized CompletableFuture disconnect() { if (channelPool != null) { channelPool.close(); channelPool = null; } - return CompletableFuture.completedFuture(OpcHttpTransport.this); + return CompletableFuture.completedFuture(Unit.VALUE); } @Override - public synchronized CompletableFuture channel() { - return acquireChannel(); - } - - @Override - public synchronized CompletableFuture sendRequest(UaRequestMessageType request) { + public synchronized CompletableFuture sendRequestMessage(UaRequestMessageType request) { LOGGER.trace("sendRequest({})", request.getClass().getSimpleName()); - return acquireChannel().thenCompose(ch -> - sendRequest(request, ch, true) - .whenComplete((response, ex) -> releaseChannel(ch)) + return acquireChannel().thenCompose(channel -> + sendRequestMessage(request, channel) + .whenComplete((response, ex) -> releaseChannel(channel)) ); } + private CompletableFuture sendRequestMessage(UaRequestMessageType request, Channel channel) { + return CompletableFuture.failedFuture(new RuntimeException("TODO")); // TODO + } + private synchronized CompletableFuture acquireChannel() { if (channelPool == null) { - channelPool = createChannelPool(client); + return CompletableFuture.failedFuture(new Exception("not connected")); } CompletableFuture future = new CompletableFuture<>(); @@ -107,8 +110,8 @@ private synchronized void releaseChannel(Channel channel) { } } - private static ChannelPool createChannelPool(UaStackClient client) { - final String endpointUrl = client.getConfig().getEndpoint().getEndpointUrl(); + private static ChannelPool createChannelPool(OpcClientTransportConfig config, ClientApplicationContext application) { + final String endpointUrl = application.getEndpoint().getEndpointUrl(); String host = EndpointUtil.getHost(endpointUrl); if (host == null) host = ""; @@ -119,7 +122,7 @@ private static ChannelPool createChannelPool(UaStackClient client) { Bootstrap bootstrap = new Bootstrap() .channel(NioSocketChannel.class) - .group(client.getConfig().getEventLoop()) + .group(config.getEventLoop()) .remoteAddress(host, port); return new SimpleChannelPool( @@ -137,12 +140,12 @@ public void channelCreated(Channel channel) throws Exception { channel.pipeline().addLast(sslContext.newHandler(channel.alloc())); } - int maxMessageSize = client.getConfig().getEncodingLimits().getMaxMessageSize(); + int maxMessageSize = application.getEncodingContext().getEncodingLimits().getMaxMessageSize(); channel.pipeline().addLast(new LoggingHandler(LogLevel.TRACE)); channel.pipeline().addLast(new HttpClientCodec()); channel.pipeline().addLast(new HttpObjectAggregator(maxMessageSize)); - channel.pipeline().addLast(new OpcClientHttpCodec(client)); + channel.pipeline().addLast(new OpcClientHttpCodec(config, application)); LOGGER.debug("channelCreated(): " + channel); } diff --git a/opc-ua-stack/stack-server/pom.xml b/opc-ua-stack/transport-websocket/pom.xml similarity index 68% rename from opc-ua-stack/stack-server/pom.xml rename to opc-ua-stack/transport-websocket/pom.xml index 93f4e28d3..49a019ec4 100644 --- a/opc-ua-stack/stack-server/pom.xml +++ b/opc-ua-stack/transport-websocket/pom.xml @@ -19,10 +19,10 @@ 2.0.0-SNAPSHOT - stack-server + transport-websocket - org.eclipse.milo.opcua.stack.server + org.eclipse.milo.opcua.stack.transport.websocket @@ -31,6 +31,11 @@ stack-core ${project.version} + + org.eclipse.milo + transport + 2.0.0-SNAPSHOT + io.netty netty-codec-http @@ -42,6 +47,19 @@ 23.0.0 provided + + + org.junit.jupiter + junit-jupiter-api + 5.9.0 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.9.0 + test + diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/websocket/OpcClientWebSocketBinaryFrameCodec.java b/opc-ua-stack/transport-websocket/src/main/java/org/eclipse/milo/opcua/stack/transport/websocket/OpcClientWebSocketBinaryFrameCodec.java similarity index 64% rename from opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/websocket/OpcClientWebSocketBinaryFrameCodec.java rename to opc-ua-stack/transport-websocket/src/main/java/org/eclipse/milo/opcua/stack/transport/websocket/OpcClientWebSocketBinaryFrameCodec.java index d77eb65fb..bee0c1a4a 100644 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/websocket/OpcClientWebSocketBinaryFrameCodec.java +++ b/opc-ua-stack/transport-websocket/src/main/java/org/eclipse/milo/opcua/stack/transport/websocket/OpcClientWebSocketBinaryFrameCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,10 +8,11 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.client.transport.websocket; +package org.eclipse.milo.opcua.stack.transport.websocket; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; @@ -19,9 +20,10 @@ import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel; -import org.eclipse.milo.opcua.stack.client.transport.uasc.UascClientAcknowledgeHandler; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; +import org.eclipse.milo.opcua.stack.transport.client.uasc.ClientSecureChannel; +import org.eclipse.milo.opcua.stack.transport.client.uasc.UascClientAcknowledgeHandler; +import org.eclipse.milo.opcua.stack.transport.client.uasc.UascClientConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,14 +33,21 @@ public class OpcClientWebSocketBinaryFrameCodec extends MessageToMessageCodec requestIdSupplier; private final CompletableFuture handshake; public OpcClientWebSocketBinaryFrameCodec( - UaStackClient client, - CompletableFuture handshake) { + UascClientConfig config, + ClientApplicationContext application, + Supplier requestIdSupplier, + CompletableFuture handshake + ) { - this.client = client; + this.config = config; + this.application = application; + this.requestIdSupplier = requestIdSupplier; this.handshake = handshake; } @@ -48,7 +57,14 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object event) throws E logger.debug("WebSocket handshake event: " + event); if (event == ClientHandshakeStateEvent.HANDSHAKE_COMPLETE) { - ctx.pipeline().addLast(new UascClientAcknowledgeHandler(client, handshake)); + var acknowledgeHandler = new UascClientAcknowledgeHandler( + config, + application, + requestIdSupplier, + handshake + ); + + ctx.pipeline().addLast(acknowledgeHandler); } } } diff --git a/opc-ua-stack/transport-websocket/src/main/java/org/eclipse/milo/opcua/stack/transport/websocket/OpcWebSocketClientTransport.java b/opc-ua-stack/transport-websocket/src/main/java/org/eclipse/milo/opcua/stack/transport/websocket/OpcWebSocketClientTransport.java new file mode 100644 index 000000000..5f4215ce7 --- /dev/null +++ b/opc-ua-stack/transport-websocket/src/main/java/org/eclipse/milo/opcua/stack/transport/websocket/OpcWebSocketClientTransport.java @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.websocket; + +import java.net.ConnectException; +import java.net.URI; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import com.digitalpetri.netty.fsm.ChannelActions; +import com.digitalpetri.netty.fsm.ChannelFsm; +import com.digitalpetri.netty.fsm.ChannelFsmConfig; +import com.digitalpetri.netty.fsm.ChannelFsmFactory; +import com.digitalpetri.netty.fsm.Event; +import com.digitalpetri.netty.fsm.State; +import com.digitalpetri.strictmachine.FsmContext; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ConnectTimeoutException; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory; +import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler; +import io.netty.handler.codec.http.websocketx.WebSocketFrameAggregator; +import io.netty.handler.codec.http.websocketx.WebSocketVersion; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; +import org.eclipse.milo.opcua.stack.core.Stack; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; +import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSecureChannelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; +import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; +import org.eclipse.milo.opcua.stack.core.util.Unit; +import org.eclipse.milo.opcua.stack.transport.client.AbstractUascClientTransport; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; +import org.eclipse.milo.opcua.stack.transport.client.uasc.ClientSecureChannel; +import org.eclipse.milo.opcua.stack.transport.client.uasc.UascClientConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; + +public class OpcWebSocketClientTransport extends AbstractUascClientTransport { + + private static final FsmContext.Key KEY_CLIENT_APPLICATION = + new FsmContext.Key<>("clientApplication", ClientApplicationContext.class); + + private static final String CHANNEL_FSM_LOGGER_NAME = "org.eclipse.milo.opcua.stack.client.ChannelFsm"; + + private final ChannelFsm channelFsm; + + private final OpcWebSocketClientTransportConfig config; + + public OpcWebSocketClientTransport(OpcWebSocketClientTransportConfig config) { + super(config); + + this.config = config; + + // TODO use configurable executors + ChannelFsmConfig fsmConfig = ChannelFsmConfig.newBuilder() + .setLazy(false) // reconnect immediately + .setMaxIdleSeconds(0) // keep alive handled by SessionFsm + .setMaxReconnectDelaySeconds(16) + .setPersistent(true) + .setChannelActions(new ClientChannelActions(config)) + .setExecutor(Stack.sharedExecutor()) + .setScheduler(Stack.sharedScheduledExecutor()) + .setLoggerName(CHANNEL_FSM_LOGGER_NAME) + .build(); + + var factory = new ChannelFsmFactory(fsmConfig); + + channelFsm = factory.newChannelFsm(); + } + + @Override + public OpcWebSocketClientTransportConfig getConfig() { + return config; + } + + @Override + public CompletableFuture connect(ClientApplicationContext applicationContext) { + channelFsm.getFsm().withContext( + (Consumer>) ctx -> + ctx.set(KEY_CLIENT_APPLICATION, applicationContext) + ); + + return channelFsm.connect().thenApply(c -> Unit.VALUE); + } + + @Override + public CompletableFuture disconnect() { + return channelFsm.disconnect().thenApply(v -> Unit.VALUE); + } + + @Override + protected CompletableFuture getChannel() { + return channelFsm.getChannel(); + } + + private class ClientChannelActions implements ChannelActions { + + private final Logger logger = LoggerFactory.getLogger(CHANNEL_FSM_LOGGER_NAME); + + private final UascClientConfig config; + + private ClientChannelActions(UascClientConfig config) { + this.config = config; + } + + @Override + public CompletableFuture connect(FsmContext ctx) { + ClientApplicationContext application = (ClientApplicationContext) ctx.get(KEY_CLIENT_APPLICATION); + + var handshakeFuture = new CompletableFuture(); + + var bootstrap = new Bootstrap(); + + bootstrap.channel(NioSocketChannel.class) + .group(OpcWebSocketClientTransport.this.config.getEventLoop()) + .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5_000) + .option(ChannelOption.TCP_NODELAY, true) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel channel) throws Exception { + String endpointUrl = application.getEndpoint().getEndpointUrl(); + String scheme = EndpointUtil.getScheme(endpointUrl); + + TransportProfile transportProfile = TransportProfile + .fromUri(application.getEndpoint().getTransportProfileUri()); + + String subprotocol; + if (transportProfile == TransportProfile.WSS_UASC_UABINARY) { + subprotocol = "opcua+cp"; + } else if (transportProfile == TransportProfile.WSS_UAJSON) { + subprotocol = "opcua+uajson"; + } else { + throw new UaException( + StatusCodes.Bad_InternalError, + "unexpected TransportProfile: " + transportProfile + ); + } + + if ("opc.wss".equalsIgnoreCase(scheme)) { + SslContext sslContext = SslContextBuilder.forClient() + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .build(); + + channel.pipeline().addLast(sslContext.newHandler(channel.alloc())); + } + + EncodingLimits encodingLimits = application.getEncodingContext().getEncodingLimits(); + + int maxMessageSize = encodingLimits.getMaxMessageSize(); + + channel.pipeline().addLast(new LoggingHandler(LogLevel.INFO)); + channel.pipeline().addLast(new HttpClientCodec()); + channel.pipeline().addLast(new HttpObjectAggregator(maxMessageSize)); + + channel.pipeline().addLast( + new WebSocketClientProtocolHandler( + WebSocketClientHandshakerFactory.newHandshaker( + new URI(endpointUrl), + WebSocketVersion.V13, + subprotocol, + true, + new DefaultHttpHeaders(), + encodingLimits.getMaxChunkSize() + ) + ) + ); + + channel.pipeline().addLast( + new WebSocketFrameAggregator(encodingLimits.getMaxMessageSize()) + ); + + // TODO when/where does the InboundUascResponseHandler get added? + // OpcClientWebSocketFrameCodec adds UascClientAcknowledgeHandler when the WS upgrade is done. + var codec = new OpcClientWebSocketBinaryFrameCodec( + config, + application, + requestId::getAndIncrement, + handshakeFuture + ); + channel.pipeline().addLast(codec); + } + }); + + String endpointUrl = application.getEndpoint().getEndpointUrl(); + + String host = EndpointUtil.getHost(endpointUrl); + assert host != null; + + int port = EndpointUtil.getPort(endpointUrl); + + bootstrap.connect(host, port).addListener((ChannelFuture f) -> { + if (!f.isSuccess()) { + Throwable cause = f.cause(); + + if (cause instanceof ConnectTimeoutException) { + handshakeFuture.completeExceptionally( + new UaException(StatusCodes.Bad_Timeout, f.cause()) + ); + } else if (cause instanceof ConnectException) { + handshakeFuture.completeExceptionally( + new UaException(StatusCodes.Bad_ConnectionRejected, f.cause()) + ); + } else { + handshakeFuture.completeExceptionally(cause); + } + } + }); + + return handshakeFuture.thenApply(ClientSecureChannel::getChannel); + } + + @Override + public CompletableFuture disconnect(FsmContext ctx, Channel channel) { + var disconnectFuture = new CompletableFuture(); + + TimerTask onTimeout = t -> channel.close().addListener( + (ChannelFutureListener) channelFuture -> + disconnectFuture.complete(null) + ); + + Timeout timeout = config.getWheelTimer().newTimeout( + onTimeout, + 5, + TimeUnit.SECONDS + ); + + channel.pipeline().addFirst(new ChannelInboundHandlerAdapter() { + @Override + public void channelInactive(ChannelHandlerContext channelContext) throws Exception { + logger.debug("[{}] channelInactive() disconnect complete", ctx.getInstanceId()); + timeout.cancel(); + disconnectFuture.complete(null); + super.channelInactive(channelContext); + } + }); + + var requestHeader = new RequestHeader( + NodeId.NULL_VALUE, + DateTime.now(), + uint(0), + uint(0), + null, + uint(0), + null + ); + + logger.debug("[{}] Sending CloseSecureChannelRequest...", ctx.getInstanceId()); + + channel.pipeline().fireUserEventTriggered(new CloseSecureChannelRequest(requestHeader)); + + return disconnectFuture; + } + + } + + +} diff --git a/opc-ua-stack/transport-websocket/src/main/java/org/eclipse/milo/opcua/stack/transport/websocket/OpcWebSocketClientTransportConfig.java b/opc-ua-stack/transport-websocket/src/main/java/org/eclipse/milo/opcua/stack/transport/websocket/OpcWebSocketClientTransportConfig.java new file mode 100644 index 000000000..d5e79cafd --- /dev/null +++ b/opc-ua-stack/transport-websocket/src/main/java/org/eclipse/milo/opcua/stack/transport/websocket/OpcWebSocketClientTransportConfig.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.websocket; + +import org.eclipse.milo.opcua.stack.transport.client.OpcClientTransportConfig; +import org.eclipse.milo.opcua.stack.transport.client.uasc.UascClientConfig; + +public interface OpcWebSocketClientTransportConfig extends OpcClientTransportConfig, UascClientConfig { +} diff --git a/opc-ua-stack/transport/pom.xml b/opc-ua-stack/transport/pom.xml new file mode 100644 index 000000000..cf0cad1fd --- /dev/null +++ b/opc-ua-stack/transport/pom.xml @@ -0,0 +1,81 @@ + + + + + 4.0.0 + + + org.eclipse.milo + opc-ua-stack + 2.0.0-SNAPSHOT + + + transport + + + org.eclipse.milo.opcua.stack.transport + + + + + org.eclipse.milo + stack-core + ${project.version} + + + com.digitalpetri.netty + netty-channel-fsm + 0.9 + + + org.jetbrains + annotations + 23.0.0 + provided + + + + org.junit.jupiter + junit-jupiter-api + 5.9.0 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.9.0 + test + + + org.junit.jupiter + junit-jupiter-params + 5.9.0 + test + + + org.slf4j + slf4j-simple + 2.0.0 + test + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + + diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/AbstractUascClientTransport.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/AbstractUascClientTransport.java new file mode 100644 index 000000000..62b8bd1ac --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/AbstractUascClientTransport.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import io.netty.channel.Channel; +import io.netty.util.Timeout; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; +import org.eclipse.milo.opcua.stack.core.util.ExecutionQueue; +import org.eclipse.milo.opcua.stack.transport.client.uasc.UascRequest; +import org.eclipse.milo.opcua.stack.transport.client.uasc.UascResponseHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractUascClientTransport implements OpcClientTransport, UascResponseHandler { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + protected final AtomicLong requestId = new AtomicLong(1L); + + protected final Map> pendingRequests = new ConcurrentHashMap<>(); + protected final Map pendingTimeouts = new ConcurrentHashMap<>(); + + protected final ExecutionQueue executionQueue; + + protected final OpcClientTransportConfig config; + + public AbstractUascClientTransport(OpcClientTransportConfig config) { + this.config = config; + + executionQueue = new ExecutionQueue(config.getExecutor(), 1); + } + + protected abstract CompletableFuture getChannel(); + + @Override + public CompletableFuture sendRequestMessage(UaRequestMessageType requestMessage) { + return getChannel().thenCompose(ch -> sendRequestMessage(requestMessage, ch)); + } + + protected CompletableFuture sendRequestMessage( + UaRequestMessageType requestMessage, + Channel channel + ) { + + var request = new UascRequest(requestId.getAndIncrement(), requestMessage); + var responseFuture = new CompletableFuture(); + + pendingRequests.put(request.getRequestId(), responseFuture); + scheduleRequestTimeout(request); + + channel.writeAndFlush(request).addListener(f -> { + if (!f.isSuccess()) { + pendingRequests.remove(request.getRequestId()); + cancelRequestTimeout(request.getRequestId()); + + responseFuture.completeExceptionally(f.cause()); + + logger.debug( + "Write failed, request={}, requestHandle={}", + requestMessage.getClass().getSimpleName(), request.getRequestId() + ); + } else { + if (logger.isTraceEnabled()) { + logger.trace( + "Write succeeded, request={}, requestId={}", + requestMessage.getClass().getSimpleName(), request.getRequestId() + ); + } + } + }); + + return responseFuture; + } + + private void scheduleRequestTimeout(UascRequest request) { + RequestHeader requestHeader = request.getRequestMessage().getRequestHeader(); + + long timeoutHint = requestHeader.getTimeoutHint() != null ? + requestHeader.getTimeoutHint().longValue() : 0L; + + if (timeoutHint > 0) { + Timeout timeout = config.getWheelTimer().newTimeout( + t -> { + Timeout removed = pendingTimeouts.remove(request.getRequestId()); + + if (removed != null && !removed.isCancelled()) { + CompletableFuture future = + pendingRequests.remove(request.getRequestId()); + + if (future != null) { + UaException exception = new UaException( + StatusCodes.Bad_Timeout, + String.format( + "requestId=%s timed out after %sms", + request.getRequestId(), timeoutHint) + ); + + future.completeExceptionally(exception); + } + } + }, + timeoutHint, + TimeUnit.MILLISECONDS + ); + + pendingTimeouts.put(request.getRequestId(), timeout); + } + } + + protected void cancelRequestTimeout(long requestId) { + Timeout timeout = pendingTimeouts.remove(requestId); + if (timeout != null) timeout.cancel(); + } + + @Override + public void handleResponse(long requestId, UaResponseMessageType responseMessage) { + CompletableFuture responseFuture = pendingRequests.remove(requestId); + + if (responseFuture != null) { + cancelRequestTimeout(requestId); + + executionQueue.submit(() -> responseFuture.complete(responseMessage)); + } else { + logger.warn("Received response for unknown request, requestId={}", requestId); + } + } + + @Override + public void handleSendFailure(long requestId, UaException exception) { + CompletableFuture responseFuture = pendingRequests.remove(requestId); + + if (responseFuture != null) { + cancelRequestTimeout(requestId); + + executionQueue.submit(() -> responseFuture.completeExceptionally(exception)); + } else { + logger.warn("Send failed for unknown request, requestId={}", requestId); + } + } + + @Override + public void handleReceiveFailure(long requestId, UaException exception) { + CompletableFuture responseFuture = pendingRequests.remove(requestId); + + if (responseFuture != null) { + cancelRequestTimeout(requestId); + + executionQueue.submit(() -> responseFuture.completeExceptionally(exception)); + } else { + logger.warn("Receive failed for unknown request, requestId={}", requestId); + } + } + + @Override + public void handleChannelError(UaException exception) { + failAndClearPending(exception); + } + + @Override + public void handleChannelInactive() { + failAndClearPending(new UaException(StatusCodes.Bad_ConnectionClosed, "connection closed")); + } + + private void failAndClearPending(UaException exception) { + pendingRequests.forEach((requestId, f) -> { + cancelRequestTimeout(requestId); + executionQueue.submit(() -> f.completeExceptionally(exception)); + }); + pendingRequests.clear(); + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/ClientApplicationContext.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/ClientApplicationContext.java new file mode 100644 index 000000000..89549ddd0 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/ClientApplicationContext.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client; + +import java.security.KeyPair; +import java.security.cert.X509Certificate; +import java.util.Optional; + +import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; + +public interface ClientApplicationContext { + + /** + * Get the {@link EndpointDescription} the client is connecting to. + * + * @return the {@link EndpointDescription} the client is connecting to. + */ + EndpointDescription getEndpoint(); + + /** + * Get the client {@link KeyPair}, if configured. + *

+ * A KeyPair is required for secured connections. + * + * @return the client {@link KeyPair}, if configured. + */ + Optional getKeyPair(); + + /** + * Get the client application instance certificate, if configured. + *

+ * An application instance certificate is required for secured connections. + * + * @return the client application instance certificate, if configured. + */ + Optional getCertificate(); + + /** + * Get the client application instance certificate chain, if configured. + *

+ * An application instance certificate chain is required for secured connections. + * + * @return the client application instance certificate chain, if configured. + */ + Optional getCertificateChain(); + + /** + * Get the client's {@link CertificateValidator}. + * + * @return the client's {@link CertificateValidator}. + */ + CertificateValidator getCertificateValidator(); + + /** + * Get the client's static {@link EncodingContext}. + * + * @return the client's static {@link EncodingContext}. + */ + EncodingContext getEncodingContext(); + + /** + * Get the client request timeout to use when opening or renewing a secure channel. + * + * @return the client request timeout to use when opening or renewing a secure channel. + */ + UInteger getRequestTimeout(); + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/OpcClientTransport.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/OpcClientTransport.java new file mode 100644 index 000000000..46019aee3 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/OpcClientTransport.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.eclipse.milo.opcua.stack.core.util.Unit; + +public interface OpcClientTransport { + + /** + * Get the {@link OpcClientTransportConfig} associated with this transport. + * + * @return the {@link OpcClientTransportConfig} associated with this transport. + */ + OpcClientTransportConfig getConfig(); + + /** + * Connect this transport implementation. + * + * @param applicationContext the {@link ClientApplicationContext} associated with this transport. + * @return a {@link CompletableFuture} that completes successfully when this transport + * connects, or completes exceptionally if an error occurred. + */ + CompletableFuture connect(ClientApplicationContext applicationContext); + + /** + * Disconnect this transport implementation. + * + * @return a {@link CompletableFuture} that completes successfully when this transport + * disconnects, or completes exceptionally if an error occurred. + */ + CompletableFuture disconnect(); + + /** + * Send a {@link UaRequestMessageType} on this transport implementation. + * + * @param requestMessage the {@link UaRequestMessageType} to send. + * @return a {@link CompletableFuture} that completes successfully with the + * {@link UaResponseMessageType} or completes exceptionally if an error occurred. + */ + CompletableFuture sendRequestMessage(UaRequestMessageType requestMessage); + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/OpcClientTransportConfig.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/OpcClientTransportConfig.java new file mode 100644 index 000000000..cb9962a26 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/OpcClientTransportConfig.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; + +import io.netty.channel.EventLoopGroup; +import io.netty.util.HashedWheelTimer; + +public interface OpcClientTransportConfig { + + /** + * Get the {@link ExecutorService} to be used by this transport. + * + * @return the {@link ExecutorService} to be used by this transport. + */ + ExecutorService getExecutor(); + + /** + * Get the {@link ScheduledExecutorService} to be used by this transport. + * + * @return the {@link ScheduledExecutorService} to be used by this transport. + */ + ScheduledExecutorService getScheduledExecutor(); + + /** + * Get the {@link EventLoopGroup} to be used by this transport. + * + * @return the {@link EventLoopGroup} to be used by this transport. + */ + EventLoopGroup getEventLoop(); + + /** + * Get the {@link HashedWheelTimer} to be used by this transport. + * + * @return the {@link HashedWheelTimer} to be used by this transport. + */ + HashedWheelTimer getWheelTimer(); + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpClientTransport.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpClientTransport.java new file mode 100644 index 000000000..e4b1d77d7 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpClientTransport.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.tcp; + +import java.net.ConnectException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import com.digitalpetri.netty.fsm.ChannelActions; +import com.digitalpetri.netty.fsm.ChannelFsm; +import com.digitalpetri.netty.fsm.ChannelFsmConfig; +import com.digitalpetri.netty.fsm.ChannelFsmFactory; +import com.digitalpetri.netty.fsm.Event; +import com.digitalpetri.netty.fsm.State; +import com.digitalpetri.strictmachine.FsmContext; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ConnectTimeoutException; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSecureChannelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; +import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; +import org.eclipse.milo.opcua.stack.core.util.Unit; +import org.eclipse.milo.opcua.stack.transport.client.AbstractUascClientTransport; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; +import org.eclipse.milo.opcua.stack.transport.client.uasc.ClientSecureChannel; +import org.eclipse.milo.opcua.stack.transport.client.uasc.InboundUascResponseHandler.DelegatingUascResponseHandler; +import org.eclipse.milo.opcua.stack.transport.client.uasc.UascClientAcknowledgeHandler; +import org.eclipse.milo.opcua.stack.transport.client.uasc.UascClientConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; + +public class OpcTcpClientTransport extends AbstractUascClientTransport { + + private static final FsmContext.Key KEY_CLIENT_APPLICATION = + new FsmContext.Key<>("clientApplication", ClientApplicationContext.class); + + private static final String CHANNEL_FSM_LOGGER_NAME = "org.eclipse.milo.opcua.stack.client.ChannelFsm"; + + private final ChannelFsm channelFsm; + + private final OpcTcpClientTransportConfig config; + + public OpcTcpClientTransport(OpcTcpClientTransportConfig config) { + super(config); + + this.config = config; + + ChannelFsmConfig fsmConfig = ChannelFsmConfig.newBuilder() + .setLazy(false) // reconnect immediately + .setMaxIdleSeconds(0) // keep alive handled by SessionFsm + .setMaxReconnectDelaySeconds(16) + .setPersistent(true) + .setChannelActions(new ClientChannelActions(config)) + .setExecutor(config.getExecutor()) + .setScheduler(config.getScheduledExecutor()) + .setLoggerName(CHANNEL_FSM_LOGGER_NAME) + .build(); + + var factory = new ChannelFsmFactory(fsmConfig); + + channelFsm = factory.newChannelFsm(); + } + + @Override + public OpcTcpClientTransportConfig getConfig() { + return config; + } + + @Override + public CompletableFuture connect(ClientApplicationContext applicationContext) { + channelFsm.getFsm().withContext( + ctx -> + ctx.set(KEY_CLIENT_APPLICATION, applicationContext) + ); + + return channelFsm.connect().thenApply(c -> Unit.VALUE); + } + + @Override + public CompletableFuture disconnect() { + return channelFsm.disconnect().thenApply(v -> Unit.VALUE); + } + + @Override + protected CompletableFuture getChannel() { + return channelFsm.getChannel(); + } + + public ChannelFsm getChannelFsm() { + return channelFsm; + } + + private class ClientChannelActions implements ChannelActions { + + private final Logger logger = LoggerFactory.getLogger(CHANNEL_FSM_LOGGER_NAME); + + private final UascClientConfig config; + + private ClientChannelActions(UascClientConfig config) { + this.config = config; + } + + @Override + public CompletableFuture connect(FsmContext ctx) { + ClientApplicationContext application = (ClientApplicationContext) ctx.get(KEY_CLIENT_APPLICATION); + + var handshakeFuture = new CompletableFuture(); + + var bootstrap = new Bootstrap(); + + bootstrap.channel(NioSocketChannel.class) + .group(OpcTcpClientTransport.this.config.getEventLoop()) + .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, + OpcTcpClientTransport.this.config.getConnectTimeout().intValue()) + .option(ChannelOption.TCP_NODELAY, true) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + var acknowledgeHandler = new UascClientAcknowledgeHandler( + config, + application, + requestId::getAndIncrement, + handshakeFuture + ); + + ch.pipeline().addLast(new DelegatingUascResponseHandler(OpcTcpClientTransport.this)); + ch.pipeline().addLast(acknowledgeHandler); + } + }); + + String endpointUrl = application.getEndpoint().getEndpointUrl(); + + String host = EndpointUtil.getHost(endpointUrl); + assert host != null; + + int port = EndpointUtil.getPort(endpointUrl); + + bootstrap.connect(host, port).addListener((ChannelFuture f) -> { + if (!f.isSuccess()) { + Throwable cause = f.cause(); + + if (cause instanceof ConnectTimeoutException) { + handshakeFuture.completeExceptionally( + new UaException(StatusCodes.Bad_Timeout, f.cause()) + ); + } else if (cause instanceof ConnectException) { + handshakeFuture.completeExceptionally( + new UaException(StatusCodes.Bad_ConnectionRejected, f.cause()) + ); + } else { + handshakeFuture.completeExceptionally(cause); + } + } + }); + + return handshakeFuture.thenApply(ClientSecureChannel::getChannel); + } + + @Override + public CompletableFuture disconnect(FsmContext ctx, Channel channel) { + var disconnectFuture = new CompletableFuture(); + + TimerTask onTimeout = t -> channel.close().addListener( + (ChannelFutureListener) channelFuture -> + disconnectFuture.complete(null) + ); + + Timeout timeout = config.getWheelTimer().newTimeout( + onTimeout, + 5, + TimeUnit.SECONDS + ); + + channel.pipeline().addFirst(new ChannelInboundHandlerAdapter() { + @Override + public void channelInactive(ChannelHandlerContext channelContext) throws Exception { + logger.debug("[{}] channelInactive() disconnect complete", ctx.getInstanceId()); + timeout.cancel(); + disconnectFuture.complete(null); + super.channelInactive(channelContext); + } + }); + + var requestHeader = new RequestHeader( + NodeId.NULL_VALUE, + DateTime.now(), + uint(0), + uint(0), + null, + uint(0), + null + ); + + logger.debug("[{}] Sending CloseSecureChannelRequest...", ctx.getInstanceId()); + + channel.pipeline().fireUserEventTriggered(new CloseSecureChannelRequest(requestHeader)); + + return disconnectFuture; + } + + } + + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpClientTransportConfig.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpClientTransportConfig.java new file mode 100644 index 000000000..824f0e054 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpClientTransportConfig.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.tcp; + +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.transport.client.OpcClientTransportConfig; +import org.eclipse.milo.opcua.stack.transport.client.uasc.UascClientConfig; + +public interface OpcTcpClientTransportConfig extends OpcClientTransportConfig, UascClientConfig { + + /** + * Get the TCP socket connect timeout, in milliseconds. + * + * @return the TCP socket connect timeout, in milliseconds. + */ + UInteger getConnectTimeout(); + + /** + * Create a new {@link OpcTcpClientTransportConfigBuilder}. + * + * @return a new {@link OpcTcpClientTransportConfigBuilder}. + */ + static OpcTcpClientTransportConfigBuilder newBuilder() { + return new OpcTcpClientTransportConfigBuilder(); + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpClientTransportConfigBuilder.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpClientTransportConfigBuilder.java new file mode 100644 index 000000000..77024016c --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpClientTransportConfigBuilder.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.tcp; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; + +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.HashedWheelTimer; +import org.eclipse.milo.opcua.stack.core.Stack; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; + +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; + +public class OpcTcpClientTransportConfigBuilder { + + private UInteger connectTimeout = uint(5_000); + private UInteger acknowledgeTimeout = uint(5_000); + private UInteger channelLifetime = uint(60 * 60 * 1000); + + private ExecutorService executor; + private ScheduledExecutorService scheduledExecutor; + private NioEventLoopGroup eventLoop; + private HashedWheelTimer wheelTimer; + + public OpcTcpClientTransportConfigBuilder setConnectTimeout(UInteger connectTimeout) { + this.connectTimeout = connectTimeout; + return this; + } + + public OpcTcpClientTransportConfigBuilder setAcknowledgeTimeout(UInteger acknowledgeTimeout) { + this.acknowledgeTimeout = acknowledgeTimeout; + return this; + } + + public OpcTcpClientTransportConfigBuilder setChannelLifetime(UInteger channelLifetime) { + this.channelLifetime = channelLifetime; + return this; + } + + public OpcTcpClientTransportConfigBuilder setExecutor(ExecutorService executor) { + this.executor = executor; + return this; + } + + public OpcTcpClientTransportConfigBuilder setScheduledExecutor(ScheduledExecutorService scheduledExecutor) { + this.scheduledExecutor = scheduledExecutor; + return this; + } + + public OpcTcpClientTransportConfigBuilder setEventLoop(NioEventLoopGroup eventLoop) { + this.eventLoop = eventLoop; + return this; + } + + public OpcTcpClientTransportConfigBuilder setWheelTimer(HashedWheelTimer wheelTimer) { + this.wheelTimer = wheelTimer; + return this; + } + + public OpcTcpClientTransportConfig build() { + if (executor == null) { + executor = Stack.sharedExecutor(); + } + if (scheduledExecutor == null) { + scheduledExecutor = Stack.sharedScheduledExecutor(); + } + if (eventLoop == null) { + eventLoop = Stack.sharedEventLoop(); + } + if (wheelTimer == null) { + wheelTimer = Stack.sharedWheelTimer(); + } + + return new OpcTcpClientTransportConfigImpl( + connectTimeout, + acknowledgeTimeout, + channelLifetime, + executor, + scheduledExecutor, + eventLoop, + wheelTimer + ); + } + + static class OpcTcpClientTransportConfigImpl implements OpcTcpClientTransportConfig { + + private final UInteger connectTimeout; + private final UInteger acknowledgeTimeout; + private final UInteger channelLifetime; + private final ExecutorService executor; + private final ScheduledExecutorService scheduledExecutor; + private final NioEventLoopGroup eventLoop; + private final HashedWheelTimer wheelTimer; + + public OpcTcpClientTransportConfigImpl( + UInteger connectTimeout, + UInteger acknowledgeTimeout, + UInteger channelLifetime, + ExecutorService executor, + ScheduledExecutorService scheduledExecutor, + NioEventLoopGroup eventLoop, + HashedWheelTimer wheelTimer + ) { + + this.connectTimeout = connectTimeout; + this.acknowledgeTimeout = acknowledgeTimeout; + this.channelLifetime = channelLifetime; + this.executor = executor; + this.scheduledExecutor = scheduledExecutor; + this.eventLoop = eventLoop; + this.wheelTimer = wheelTimer; + } + + + @Override + public UInteger getConnectTimeout() { + return connectTimeout; + } + + @Override + public UInteger getAcknowledgeTimeout() { + return acknowledgeTimeout; + } + + @Override + public UInteger getChannelLifetime() { + return channelLifetime; + } + + @Override + public ExecutorService getExecutor() { + return executor; + } + + @Override + public ScheduledExecutorService getScheduledExecutor() { + return scheduledExecutor; + } + + @Override + public NioEventLoopGroup getEventLoop() { + return eventLoop; + } + + @Override + public HashedWheelTimer getWheelTimer() { + return wheelTimer; + } + + } + +} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/ClientSecureChannel.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/ClientSecureChannel.java similarity index 65% rename from opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/ClientSecureChannel.java rename to opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/ClientSecureChannel.java index 692e2a0bf..0e6db6537 100644 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/ClientSecureChannel.java +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/ClientSecureChannel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,34 +8,23 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.client.transport.uasc; +package org.eclipse.milo.opcua.stack.transport.client.uasc; import java.security.KeyPair; import java.security.cert.X509Certificate; -import java.util.Arrays; import java.util.List; import com.google.common.base.MoreObjects; import io.netty.channel.Channel; -import io.netty.util.AttributeKey; import io.netty.util.DefaultAttributeMap; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.core.StatusCodes; -import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.channel.ChannelSecurity; import org.eclipse.milo.opcua.stack.core.channel.SecureChannel; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; -import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; -import org.eclipse.milo.opcua.stack.core.util.CertificateUtil; -import org.eclipse.milo.opcua.stack.core.util.LongSequence; public class ClientSecureChannel extends DefaultAttributeMap implements SecureChannel { - public static final AttributeKey KEY_REQUEST_ID_SEQUENCE = - AttributeKey.valueOf("request-id-sequence"); - private volatile Channel channel; private volatile long channelId = 0; private volatile ChannelSecurity channelSecurity; @@ -168,52 +157,4 @@ public String toString() { .toString(); } - public static ClientSecureChannel fromConfig(UaStackClientConfig config) throws UaException { - EndpointDescription endpoint = config.getEndpoint(); - - SecurityPolicy securityPolicy = SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()); - - if (securityPolicy == SecurityPolicy.None) { - return new ClientSecureChannel( - securityPolicy, - endpoint.getSecurityMode() - ); - } else { - KeyPair keyPair = config.getKeyPair().orElseThrow(() -> - new UaException( - StatusCodes.Bad_ConfigurationError, - "no KeyPair configured") - ); - - X509Certificate certificate = config.getCertificate().orElseThrow(() -> - new UaException( - StatusCodes.Bad_ConfigurationError, - "no certificate configured") - ); - - List certificateChain = Arrays.asList( - config.getCertificateChain().orElseThrow(() -> - new UaException( - StatusCodes.Bad_ConfigurationError, - "no certificate chain configured")) - ); - - X509Certificate remoteCertificate = CertificateUtil - .decodeCertificate(endpoint.getServerCertificate().bytes()); - - List remoteCertificateChain = CertificateUtil - .decodeCertificates(endpoint.getServerCertificate().bytes()); - - return new ClientSecureChannel( - keyPair, - certificate, - certificateChain, - remoteCertificate, - remoteCertificateChain, - securityPolicy, - endpoint.getSecurityMode() - ); - } - } - } diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/InboundUascResponseHandler.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/InboundUascResponseHandler.java new file mode 100644 index 000000000..fb3a6f99a --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/InboundUascResponseHandler.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.uasc; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.channel.messages.ErrorMessage; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; + +public abstract class InboundUascResponseHandler + extends SimpleChannelInboundHandler implements UascResponseHandler { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, UascResponse response) { + if (response.isSuccess()) { + handleResponse(response.getRequestId(), response.getResponseMessage()); + } else { + handleReceiveFailure(response.getRequestId(), response.getException()); + } + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof UascResponse) { + UascResponse response = (UascResponse) evt; + assert response.isFailure(); + + handleSendFailure(response.getRequestId(), response.getException()); + } else if (evt instanceof ErrorMessage) { + ErrorMessage errorMessage = (ErrorMessage) evt; + StatusCode statusCode = errorMessage.getError(); + + handleChannelError(new UaException(statusCode, errorMessage.getReason())); + } + + super.userEventTriggered(ctx, evt); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + handleChannelInactive(); + + super.channelInactive(ctx); + } + + public static class DelegatingUascResponseHandler extends InboundUascResponseHandler { + + private final UascResponseHandler delegate; + + public DelegatingUascResponseHandler(UascResponseHandler delegate) { + this.delegate = delegate; + } + + @Override + public void handleResponse(long requestId, UaResponseMessageType responseMessage) { + delegate.handleResponse(requestId, responseMessage); + } + + @Override + public void handleSendFailure(long requestId, UaException exception) { + delegate.handleSendFailure(requestId, exception); + } + + @Override + public void handleReceiveFailure(long requestId, UaException exception) { + delegate.handleReceiveFailure(requestId, exception); + } + + @Override + public void handleChannelError(UaException exception) { + delegate.handleChannelError(exception); + } + + @Override + public void handleChannelInactive() { + delegate.handleChannelInactive(); + } + + } + +} diff --git a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/UascClientAcknowledgeHandler.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientAcknowledgeHandler.java similarity index 72% rename from opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/UascClientAcknowledgeHandler.java rename to opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientAcknowledgeHandler.java index 35b95b879..9f7e78334 100644 --- a/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/UascClientAcknowledgeHandler.java +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientAcknowledgeHandler.java @@ -8,66 +8,66 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.client.transport.uasc; +package org.eclipse.milo.opcua.stack.transport.client.uasc; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; import com.google.common.primitives.Ints; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageCodec; -import io.netty.util.AttributeKey; import io.netty.util.Timeout; -import org.eclipse.milo.opcua.stack.client.UaStackClient; -import org.eclipse.milo.opcua.stack.client.UaStackClientConfig; -import org.eclipse.milo.opcua.stack.client.transport.UaTransportRequest; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.channel.ChannelParameters; import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; -import org.eclipse.milo.opcua.stack.core.channel.SerializationQueue; -import org.eclipse.milo.opcua.stack.core.channel.headers.HeaderDecoder; import org.eclipse.milo.opcua.stack.core.channel.messages.AcknowledgeMessage; import org.eclipse.milo.opcua.stack.core.channel.messages.ErrorMessage; import org.eclipse.milo.opcua.stack.core.channel.messages.HelloMessage; import org.eclipse.milo.opcua.stack.core.channel.messages.MessageType; import org.eclipse.milo.opcua.stack.core.channel.messages.TcpMessageDecoder; import org.eclipse.milo.opcua.stack.core.channel.messages.TcpMessageEncoder; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class UascClientAcknowledgeHandler extends ByteToMessageCodec implements HeaderDecoder { +public class UascClientAcknowledgeHandler extends ByteToMessageCodec { - static final AttributeKey> KEY_AWAITING_HANDSHAKE = - AttributeKey.valueOf("awaiting-handshake"); + private static final long PROTOCOL_VERSION = 0L; private final Logger logger = LoggerFactory.getLogger(getClass()); - private final List awaitingHandshake = new CopyOnWriteArrayList<>(); + private final List awaitingHandshake = + Collections.synchronizedList(new ArrayList<>()); + private final AtomicBoolean helloSent = new AtomicBoolean(false); private Timeout helloTimeout; - private final UaStackClientConfig config; - private final ClientSecureChannel secureChannel; - - private final UaStackClient client; + private final UascClientConfig config; + private final ClientApplicationContext application; + private final Supplier requestIdSupplier; private final CompletableFuture handshakeFuture; public UascClientAcknowledgeHandler( - UaStackClient client, - CompletableFuture handshakeFuture) throws UaException { - - this.client = client; + UascClientConfig config, + ClientApplicationContext application, + Supplier requestIdSupplier, + CompletableFuture handshakeFuture + ) { + + this.config = config; + this.application = application; + this.requestIdSupplier = requestIdSupplier; this.handshakeFuture = handshakeFuture; - - config = client.getConfig(); - secureChannel = ClientSecureChannel.fromConfig(config); } /* @@ -102,19 +102,33 @@ public void handlerAdded(ChannelHandlerContext ctx) throws Exception { super.handlerAdded(ctx); } + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + logger.error( + "[remote={}] Exception caught: {}", + ctx.channel().remoteAddress(), cause.getMessage(), cause); + + // If the handshake hasn't completed yet this cause will be more + // accurate than the generic "connection closed" exception that + // channelInactive() will use. + handshakeFuture.completeExceptionally(cause); + + ctx.close(); + } + private void sendHello(ChannelHandlerContext ctx) throws UaException { helloTimeout = startHelloTimeout(ctx); - secureChannel.setChannel(ctx.channel()); + String endpointUrl = application.getEndpoint().getEndpointUrl(); - String endpointUrl = config.getEndpoint().getEndpointUrl(); + EncodingLimits encodingLimits = application.getEncodingContext().getEncodingLimits(); - HelloMessage hello = new HelloMessage( + var hello = new HelloMessage( PROTOCOL_VERSION, - config.getEncodingLimits().getMaxChunkSize(), - config.getEncodingLimits().getMaxChunkSize(), - config.getEncodingLimits().getMaxMessageSize(), - config.getEncodingLimits().getMaxChunkCount(), + encodingLimits.getMaxChunkSize(), + encodingLimits.getMaxChunkSize(), + encodingLimits.getMaxMessageSize(), + encodingLimits.getMaxChunkCount(), endpointUrl ); @@ -142,15 +156,15 @@ private Timeout startHelloTimeout(ChannelHandlerContext ctx) { } @Override - protected void encode(ChannelHandlerContext ctx, UaTransportRequest message, ByteBuf out) { + protected void encode(ChannelHandlerContext ctx, UaRequestMessageType message, ByteBuf byteBuf) throws Exception { awaitingHandshake.add(message); } @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { - int maxChunkSize = config.getEncodingLimits().getMaxChunkSize(); + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List list) throws Exception { + int maxChunkSize = application.getEncodingContext().getEncodingLimits().getMaxChunkSize(); - if (buffer.readableBytes() >= HEADER_LENGTH) { + if (buffer.readableBytes() >= 8) { int messageLength = getMessageLength(buffer, maxChunkSize); if (buffer.readableBytes() >= messageLength) { @@ -179,7 +193,8 @@ private void onAcknowledge(ChannelHandlerContext ctx, ByteBuf buffer) { helloTimeout = null; handshakeFuture.completeExceptionally( new UaException(StatusCodes.Bad_Timeout, - "timed out waiting for acknowledge")); + "timed out waiting for acknowledge") + ); ctx.close(); return; } @@ -197,11 +212,13 @@ private void onAcknowledge(ChannelHandlerContext ctx, ByteBuf buffer) { long remoteMaxChunkCount = acknowledge.getMaxChunkCount(); if (PROTOCOL_VERSION > remoteProtocolVersion) { - logger.warn("Client protocol version ({}) does not match server protocol version ({}).", - PROTOCOL_VERSION, remoteProtocolVersion); + logger.warn( + "Client protocol version ({}) does not match server protocol version ({}).", + PROTOCOL_VERSION, remoteProtocolVersion + ); } - EncodingLimits encodingLimits = config.getEncodingLimits(); + EncodingLimits encodingLimits = application.getEncodingContext().getEncodingLimits(); /* Our receive buffer size is determined by the remote send buffer size. */ long localReceiveBufferSize = Math.min(remoteSendBufferSize, encodingLimits.getMaxChunkSize()); @@ -215,7 +232,7 @@ private void onAcknowledge(ChannelHandlerContext ctx, ByteBuf buffer) { /* Max chunk count the remote can send us; not influenced by remote configuration. */ long localMaxChunkCount = encodingLimits.getMaxChunkCount(); - ChannelParameters parameters = new ChannelParameters( + var channelParameters = new ChannelParameters( Ints.saturatedCast(localMaxMessageSize), Ints.saturatedCast(localReceiveBufferSize), Ints.saturatedCast(localSendBufferSize), @@ -226,23 +243,17 @@ private void onAcknowledge(ChannelHandlerContext ctx, ByteBuf buffer) { Ints.saturatedCast(remoteMaxChunkCount) ); - ctx.channel().attr(KEY_AWAITING_HANDSHAKE).set(awaitingHandshake); - ctx.executor().execute(() -> { - SerializationQueue serializationQueue = new SerializationQueue( - config.getExecutor(), - parameters, - client.getStaticEncodingContext() - ); - - UascClientMessageHandler handler = new UascClientMessageHandler( + var messageHandler = new UascClientMessageHandler( config, - secureChannel, - serializationQueue, - handshakeFuture + application, + requestIdSupplier, + handshakeFuture, + awaitingHandshake, + channelParameters ); - ctx.pipeline().addLast(handler); + ctx.pipeline().addFirst(messageHandler); }); } @@ -252,14 +263,18 @@ private void onError(ChannelHandlerContext ctx, ByteBuf buffer) { StatusCode statusCode = errorMessage.getError(); logger.error( - "[remote={}] Received error message: {}", - ctx.channel().remoteAddress(), errorMessage); + "[remote={}] received error message: {}", + ctx.channel().remoteAddress(), errorMessage + ); handshakeFuture.completeExceptionally(new UaException(statusCode, errorMessage.getReason())); + + ctx.fireUserEventTriggered(errorMessage); } catch (UaException e) { logger.error( - "[remote={}] An exception occurred while decoding an error message: {}", - ctx.channel().remoteAddress(), e.getMessage(), e); + "[remote={}] an exception occurred while decoding an error message: {}", + ctx.channel().remoteAddress(), e.getMessage(), e + ); handshakeFuture.completeExceptionally(e); } finally { @@ -267,18 +282,17 @@ private void onError(ChannelHandlerContext ctx, ByteBuf buffer) { } } - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - logger.error( - "[remote={}] Exception caught: {}", - ctx.channel().remoteAddress(), cause.getMessage(), cause); + private static int getMessageLength(ByteBuf buffer, int maxMessageLength) throws UaException { + long messageLength = buffer.getUnsignedIntLE(buffer.readerIndex() + 4); - // If the handshake hasn't completed yet this cause will be more - // accurate than the generic "connection closed" exception that - // channelInactive() will use. - handshakeFuture.completeExceptionally(cause); - - ctx.close(); + if (messageLength <= maxMessageLength) { + return (int) messageLength; + } else { + throw new UaException( + StatusCodes.Bad_TcpMessageTooLarge, + String.format("max message length exceeded (%s > %s)", messageLength, maxMessageLength) + ); + } } } diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientConfig.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientConfig.java new file mode 100644 index 000000000..e04716a55 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientConfig.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.uasc; + +import io.netty.util.HashedWheelTimer; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; + +public interface UascClientConfig { + + /** + * Get the timeout, in milliseconds, that an "Acknowledge" message must arrive by in response + * to the client "Hello" message. + * + * @return the timeout, in milliseconds, that an "Acknowledge" message must arrive by. + */ + UInteger getAcknowledgeTimeout(); + + /** + * Get the requested secure channel lifetime. The server may revise this value. + * + * @return the requested secure channel lifetime. + */ + UInteger getChannelLifetime(); + + /** + * Get the Netty {@link HashedWheelTimer} to use for scheduling transport layer timeouts. + * + * @return the Netty {@link HashedWheelTimer} to use for scheduling transport layer timeouts. + */ + HashedWheelTimer getWheelTimer(); + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientMessageHandler.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientMessageHandler.java new file mode 100644 index 000000000..41dc49e19 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientMessageHandler.java @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.uasc; + +import java.security.KeyPair; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.CompositeByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageCodec; +import io.netty.util.ReferenceCountUtil; +import io.netty.util.Timeout; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.UaSerializationException; +import org.eclipse.milo.opcua.stack.core.UaServiceFaultException; +import org.eclipse.milo.opcua.stack.core.channel.ChannelParameters; +import org.eclipse.milo.opcua.stack.core.channel.ChannelSecurity; +import org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder; +import org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder.DecodedMessage; +import org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder; +import org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder.EncodedMessage; +import org.eclipse.milo.opcua.stack.core.channel.MessageAbortException; +import org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException; +import org.eclipse.milo.opcua.stack.core.channel.MessageEncodeException; +import org.eclipse.milo.opcua.stack.core.channel.headers.AsymmetricSecurityHeader; +import org.eclipse.milo.opcua.stack.core.channel.messages.ErrorMessage; +import org.eclipse.milo.opcua.stack.core.channel.messages.MessageType; +import org.eclipse.milo.opcua.stack.core.channel.messages.TcpMessageDecoder; +import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryDecoder; +import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryEncoder; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +import org.eclipse.milo.opcua.stack.core.types.UaMessageType; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.enumerated.SecurityTokenRequestType; +import org.eclipse.milo.opcua.stack.core.types.structured.ChannelSecurityToken; +import org.eclipse.milo.opcua.stack.core.types.structured.CloseSecureChannelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelResponse; +import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; +import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; +import org.eclipse.milo.opcua.stack.core.util.BufferUtil; +import org.eclipse.milo.opcua.stack.core.util.CertificateUtil; +import org.eclipse.milo.opcua.stack.core.util.NonceUtil; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; + +public class UascClientMessageHandler extends ByteToMessageCodec { + + private static final long PROTOCOL_VERSION = 0L; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final AtomicReference headerRef = new AtomicReference<>(); + + private List chunkBuffers = new ArrayList<>(); + + private ScheduledFuture renewFuture; + private Timeout secureChannelTimeout; + + private ClientSecureChannel secureChannel; + + private final OpcUaBinaryDecoder binaryDecoder; + private final OpcUaBinaryEncoder binaryEncoder; + private final ChunkDecoder chunkDecoder; + private final ChunkEncoder chunkEncoder; + + private final UascClientConfig config; + private final ClientApplicationContext application; + private final Supplier requestIdSupplier; + private final CompletableFuture handshakeFuture; + private final ChannelParameters channelParameters; + + public UascClientMessageHandler( + UascClientConfig config, + ClientApplicationContext application, + Supplier requestIdSupplier, + CompletableFuture handshakeFuture, + List awaitingHandshake, + ChannelParameters channelParameters + ) { + + this.config = config; + this.application = application; + this.requestIdSupplier = requestIdSupplier; + this.handshakeFuture = handshakeFuture; + this.channelParameters = channelParameters; + + binaryDecoder = new OpcUaBinaryDecoder(application.getEncodingContext()); + binaryEncoder = new OpcUaBinaryEncoder(application.getEncodingContext()); + + chunkDecoder = new ChunkDecoder(channelParameters, application.getEncodingContext().getEncodingLimits()); + chunkEncoder = new ChunkEncoder(channelParameters); + + handshakeFuture.thenAccept(sc -> { + Channel channel = sc.getChannel(); + + channel.eventLoop().execute(() -> { + logger.debug( + "{} message(s) queued before handshake completed; sending now.", + awaitingHandshake.size() + ); + + awaitingHandshake.forEach(channel::writeAndFlush); + awaitingHandshake.clear(); + }); + }); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (renewFuture != null) { + renewFuture.cancel(false); + } + + UaException exception = new UaException( + StatusCodes.Bad_ConnectionClosed, + "connection closed" + ); + + handshakeFuture.completeExceptionally(exception); + + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + logger.error( + "[remote={}] Exception caught: {}", + ctx.channel().remoteAddress(), cause.getMessage(), cause); + + chunkBuffers.forEach(ReferenceCountUtil::safeRelease); + chunkBuffers.clear(); + + // If the handshake hasn't completed yet this cause will be more + // accurate than the generic "connection closed" exception that + // channelInactive() will use. + handshakeFuture.completeExceptionally(cause); + + ctx.close(); + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + secureChannel = newSecureChannel(application); + secureChannel.setChannel(ctx.channel()); + + SecurityTokenRequestType requestType = secureChannel.getChannelId() == 0 ? + SecurityTokenRequestType.Issue : SecurityTokenRequestType.Renew; + + secureChannelTimeout = config.getWheelTimer().newTimeout( + timeout -> { + if (!timeout.isCancelled()) { + handshakeFuture.completeExceptionally( + new UaException( + StatusCodes.Bad_Timeout, + "timed out waiting for secure channel") + ); + ctx.close(); + } + }, + application.getRequestTimeout().longValue(), TimeUnit.MILLISECONDS + ); + + logger.debug("OpenSecureChannel timeout scheduled for +{}ms", application.getRequestTimeout()); + + sendOpenSecureChannelRequest(ctx, requestType); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { + if (evt instanceof CloseSecureChannelRequest) { + sendCloseSecureChannelRequest(ctx, (CloseSecureChannelRequest) evt); + } + } + + @Override + protected void encode(ChannelHandlerContext ctx, UascRequest request, ByteBuf buffer) throws Exception { + ByteBuf messageBuffer = BufferUtil.pooledBuffer(); + + try { + binaryEncoder.setBuffer(messageBuffer); + binaryEncoder.encodeMessage(null, request.getRequestMessage()); + + checkMessageSize(messageBuffer); + + EncodedMessage encodedMessage = chunkEncoder.encodeSymmetric( + secureChannel, + request.getRequestId(), + messageBuffer, + MessageType.SecureMessage + ); + + List messageChunks = encodedMessage.getMessageChunks(); + + CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); + + for (ByteBuf chunk : messageChunks) { + chunkComposite.addComponent(chunk); + chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); + } + + ctx.writeAndFlush(chunkComposite, ctx.voidPromise()); + } catch (MessageEncodeException e) { + logger.error("Error encoding {}: {}", request, e.getMessage(), e); + + UaException responseException = UaException.extract(e) + .orElseGet(() -> new UaException(e)); + + UascResponse response = UascResponse + .failure(request.getRequestId(), responseException); + + ctx.fireUserEventTriggered(response); + + // failure during symmetric encoding is fatal + ctx.close(); + } catch (UaSerializationException e) { + logger.error("Error serializing {}: {}", request, e.getMessage(), e); + + UaException responseException = UaException.extract(e) + .orElseGet(() -> new UaException(e)); + + UascResponse response = UascResponse + .failure(request.getRequestId(), responseException); + + ctx.fireUserEventTriggered(response); + } finally { + messageBuffer.release(); + } + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { + if (buffer.readableBytes() >= 8) { + int messageLength = getMessageLength(buffer, channelParameters.getLocalReceiveBufferSize()); + + if (buffer.readableBytes() >= messageLength) { + MessageType messageType = MessageType.fromMediumInt( + buffer.getMediumLE(buffer.readerIndex()) + ); + + switch (messageType) { + case OpenSecureChannel: + onOpenSecureChannel(ctx, buffer.readSlice(messageLength)); + break; + + case SecureMessage: + onSecureMessage(ctx, buffer.readSlice(messageLength), out); + break; + + case Error: + onError(ctx, buffer.readSlice(messageLength)); + break; + + default: + throw new UaException( + StatusCodes.Bad_TcpMessageTypeInvalid, + "unexpected MessageType: " + messageType + ); + } + } + } + } + + private void onSecureMessage(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws UaException { + buffer.skipBytes(3 + 1 + 4); // skip messageType, chunkType, messageSize + + long secureChannelId = buffer.readUnsignedIntLE(); + if (secureChannelId != secureChannel.getChannelId()) { + throw new UaException( + StatusCodes.Bad_SecureChannelIdInvalid, + "invalid secure channel id: " + secureChannelId + ); + } + + if (accumulateChunk(buffer)) { + final List buffersToDecode = chunkBuffers; + chunkBuffers = new ArrayList<>(getMaxChunkCount()); + + ByteBuf messageBuffer = null; + + try { + DecodedMessage decodedMessage = chunkDecoder.decodeSymmetric(secureChannel, buffersToDecode); + + messageBuffer = decodedMessage.getMessage(); + + binaryDecoder.setBuffer(messageBuffer); + UaMessageType message = binaryDecoder.decodeMessage(null); + + if (message instanceof ServiceFault) { + ServiceFault serviceFault = (ServiceFault) message; + + UascResponse response = UascResponse.failure( + decodedMessage.getRequestId(), + new UaServiceFaultException(serviceFault) + ); + out.add(response); + } else if (message instanceof UaResponseMessageType) { + UascResponse response = UascResponse.success( + decodedMessage.getRequestId(), + (UaResponseMessageType) message + ); + out.add(response); + } else { + UascResponse response = UascResponse.failure( + decodedMessage.getRequestId(), + new UaException(StatusCodes.Bad_UnknownResponse, message.getClass().getSimpleName()) + ); + out.add(response); + } + } catch (MessageAbortException e) { + logger.warn( + "Received message abort chunk; error={}, reason={}", + e.getStatusCode(), e.getMessage() + ); + + out.add( + UascResponse.failure( + e.getRequestId(), + new UaException(e.getStatusCode(), e.getMessage()) + ) + ); + } catch (MessageDecodeException e) { + logger.error("Error decoding symmetric message", e); + + ctx.close(); + } finally { + if (messageBuffer != null) { + messageBuffer.release(); + } + } + } + } + + private void onOpenSecureChannel(ChannelHandlerContext ctx, ByteBuf buffer) throws UaException { + if (secureChannelTimeout != null) { + if (secureChannelTimeout.cancel()) { + logger.debug("OpenSecureChannel timeout canceled"); + + secureChannelTimeout = null; + } else { + logger.warn("timed out waiting for secure channel"); + + handshakeFuture.completeExceptionally( + new UaException(StatusCodes.Bad_Timeout, + "timed out waiting for secure channel")); + ctx.close(); + return; + } + } + + buffer.skipBytes(3 + 1 + 4 + 4); // skip messageType, chunkType, messageSize, secureChannelId + + AsymmetricSecurityHeader securityHeader = AsymmetricSecurityHeader.decode( + buffer, + application.getEncodingContext().getEncodingLimits() + ); + + if (headerRef.compareAndSet(null, securityHeader)) { + // first time we've received the header; validate and verify the server certificate + CertificateValidator certificateValidator = application.getCertificateValidator(); + + SecurityPolicy securityPolicy = SecurityPolicy.fromUri(securityHeader.getSecurityPolicyUri()); + + if (securityPolicy != SecurityPolicy.None) { + ByteString serverCertificateBytes = securityHeader.getSenderCertificate(); + + List serverCertificateChain = + CertificateUtil.decodeCertificates(serverCertificateBytes.bytesOrEmpty()); + + certificateValidator.validateCertificateChain(serverCertificateChain); + } + } else { + if (!securityHeader.equals(headerRef.get())) { + throw new UaException( + StatusCodes.Bad_SecurityChecksFailed, + "subsequent AsymmetricSecurityHeader did not match" + ); + } + } + + if (accumulateChunk(buffer)) { + final List buffersToDecode = chunkBuffers; + chunkBuffers = new ArrayList<>(getMaxChunkCount()); + + ByteBuf messageBuffer = null; + + try { + DecodedMessage decodedMessage = chunkDecoder + .decodeAsymmetric(secureChannel, buffersToDecode); + + messageBuffer = decodedMessage.getMessage(); + + binaryDecoder.setBuffer(messageBuffer); + UaResponseMessageType responseMessage = (UaResponseMessageType) binaryDecoder.decodeMessage(null); + + StatusCode serviceResult = responseMessage.getResponseHeader().getServiceResult(); + + if (serviceResult.isGood()) { + OpenSecureChannelResponse response = (OpenSecureChannelResponse) responseMessage; + logger.debug("Received OpenSecureChannelResponse."); + + secureChannel.setChannelId(response.getSecurityToken().getChannelId().longValue()); + + installSecurityToken(ctx, response); + + handshakeFuture.complete(secureChannel); + } else { + ServiceFault serviceFault = (responseMessage instanceof ServiceFault) ? + (ServiceFault) responseMessage : new ServiceFault(responseMessage.getResponseHeader()); + + handshakeFuture.completeExceptionally(new UaServiceFaultException(serviceFault)); + ctx.close(); + } + } catch (MessageAbortException e) { + logger.warn( + "Received message abort chunk; error={}, reason={}", + e.getStatusCode(), e.getMessage() + ); + } catch (MessageDecodeException e) { + logger.error("Error decoding asymmetric message", e); + + handshakeFuture.completeExceptionally(e); + + ctx.close(); + } catch (Exception e) { + logger.error("Error decoding OpenSecureChannelResponse", e); + + handshakeFuture.completeExceptionally(e); + + ctx.close(); + } finally { + if (messageBuffer != null) { + messageBuffer.release(); + } + } + } + } + + private void installSecurityToken( + ChannelHandlerContext ctx, + OpenSecureChannelResponse response + ) throws UaException { + + if (response.getServerProtocolVersion().longValue() < PROTOCOL_VERSION) { + throw new UaException( + StatusCodes.Bad_ProtocolVersionUnsupported, + "server protocol version unsupported: " + response.getServerProtocolVersion() + ); + } + + ChannelSecurity.SecurityKeys newKeys = null; + ChannelSecurityToken newToken = response.getSecurityToken(); + + if (secureChannel.isSymmetricSigningEnabled()) { + ByteString serverNonce = response.getServerNonce(); + + NonceUtil.validateNonce(serverNonce, secureChannel.getSecurityPolicy()); + + secureChannel.setRemoteNonce(serverNonce); + + newKeys = ChannelSecurity.generateKeyPair( + secureChannel, + secureChannel.getLocalNonce(), + secureChannel.getRemoteNonce() + ); + } + + ChannelSecurity oldSecrets = secureChannel.getChannelSecurity(); + ChannelSecurity.SecurityKeys oldKeys = oldSecrets != null ? oldSecrets.getCurrentKeys() : null; + ChannelSecurityToken oldToken = oldSecrets != null ? oldSecrets.getCurrentToken() : null; + + secureChannel.setChannelSecurity(new ChannelSecurity(newKeys, newToken, oldKeys, oldToken)); + + DateTime createdAt = response.getSecurityToken().getCreatedAt(); + long revisedLifetime = response.getSecurityToken().getRevisedLifetime().longValue(); + + if (revisedLifetime > 0) { + long renewAt = (long) (revisedLifetime * 0.75); + renewFuture = ctx.executor().schedule( + () -> + sendOpenSecureChannelRequest(ctx, SecurityTokenRequestType.Renew), + renewAt, TimeUnit.MILLISECONDS + ); + } else { + logger.warn("Server revised secure channel lifetime to 0; renewal will not occur."); + } + + ctx.executor().execute(() -> { + // SecureChannel is ready; remove the acknowledge handler. + if (ctx.pipeline().get(UascClientAcknowledgeHandler.class) != null) { + ctx.pipeline().remove(UascClientAcknowledgeHandler.class); + } + }); + + ChannelSecurity channelSecurity = secureChannel.getChannelSecurity(); + + long currentTokenId = channelSecurity.getCurrentToken().getTokenId().longValue(); + + long previousTokenId = channelSecurity.getPreviousToken() + .map(t -> t.getTokenId().longValue()).orElse(-1L); + + logger.debug( + "SecureChannel id={}, currentTokenId={}, previousTokenId={}, lifetime={}ms, createdAt={}", + secureChannel.getChannelId(), currentTokenId, previousTokenId, revisedLifetime, createdAt + ); + } + + private void onError(ChannelHandlerContext ctx, ByteBuf buffer) { + try { + ErrorMessage errorMessage = TcpMessageDecoder.decodeError(buffer); + StatusCode statusCode = errorMessage.getError(); + + logger.error("[remote={}] errorMessage={}", ctx.channel().remoteAddress(), errorMessage); + + handshakeFuture.completeExceptionally(new UaException(statusCode, errorMessage.getReason())); + + ctx.fireUserEventTriggered(errorMessage); + } catch (UaException e) { + logger.error( + "[remote={}] An exception occurred while decoding an error message: {}", + ctx.channel().remoteAddress(), e.getMessage(), e); + + handshakeFuture.completeExceptionally(e); + } finally { + ctx.close(); + } + } + + private boolean accumulateChunk(ByteBuf buffer) throws UaException { + int maxChunkCount = getMaxChunkCount(); + int maxChunkSize = getMaxChunkSize(); + + int chunkSize = buffer.readerIndex(0).readableBytes(); + + if (chunkSize > maxChunkSize) { + throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, + String.format("max chunk size exceeded (%s)", maxChunkSize)); + } + + chunkBuffers.add(buffer.retain()); + + if (maxChunkCount > 0 && chunkBuffers.size() > maxChunkCount) { + throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, + String.format("max chunk count exceeded (%s)", maxChunkCount)); + } + + char chunkType = (char) buffer.getByte(3); + + return (chunkType == 'A' || chunkType == 'F'); + } + + private void sendOpenSecureChannelRequest(ChannelHandlerContext ctx, SecurityTokenRequestType requestType) { + ByteString clientNonce = secureChannel.isSymmetricSigningEnabled() ? + NonceUtil.generateNonce(secureChannel.getSecurityPolicy()) : + ByteString.NULL_VALUE; + + secureChannel.setLocalNonce(clientNonce); + + var header = new RequestHeader( + null, + DateTime.now(), + uint(0), + uint(0), + null, + application.getRequestTimeout(), + null + ); + + var request = new OpenSecureChannelRequest( + header, + uint(PROTOCOL_VERSION), + requestType, + secureChannel.getMessageSecurityMode(), + secureChannel.getLocalNonce(), + config.getChannelLifetime() + ); + + ByteBuf messageBuffer = BufferUtil.pooledBuffer(); + + try { + binaryEncoder.setBuffer(messageBuffer); + binaryEncoder.encodeMessage(null, request); + + checkMessageSize(messageBuffer); + + EncodedMessage encodedMessage = chunkEncoder.encodeAsymmetric( + secureChannel, + requestIdSupplier.get(), + messageBuffer, + MessageType.OpenSecureChannel + ); + + CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); + + for (ByteBuf chunk : encodedMessage.getMessageChunks()) { + chunkComposite.addComponent(chunk); + chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); + } + + ctx.writeAndFlush(chunkComposite, ctx.voidPromise()); + + ChannelSecurity channelSecurity = secureChannel.getChannelSecurity(); + + long currentTokenId = -1L; + if (channelSecurity != null) { + currentTokenId = channelSecurity.getCurrentToken().getTokenId().longValue(); + } + + long previousTokenId = -1L; + if (channelSecurity != null) { + previousTokenId = channelSecurity.getPreviousToken() + .map(token -> token.getTokenId().longValue()) + .orElse(-1L); + } + + logger.debug( + "Sent OpenSecureChannelRequest ({}, id={}, currentToken={}, previousToken={}).", + request.getRequestType(), + secureChannel.getChannelId(), + currentTokenId, + previousTokenId + ); + } catch (MessageEncodeException e) { + logger.error("Error encoding {}: {}", request, e.getMessage(), e); + + ctx.close(); + } finally { + messageBuffer.release(); + } + } + + private void sendCloseSecureChannelRequest(ChannelHandlerContext ctx, CloseSecureChannelRequest request) { + ByteBuf messageBuffer = BufferUtil.pooledBuffer(); + + try { + binaryEncoder.setBuffer(messageBuffer); + binaryEncoder.encodeMessage(null, request); + + checkMessageSize(messageBuffer); + + EncodedMessage encodedMessage = chunkEncoder.encodeSymmetric( + secureChannel, + requestIdSupplier.get(), + messageBuffer, + MessageType.CloseSecureChannel + ); + + CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); + + for (ByteBuf chunk : encodedMessage.getMessageChunks()) { + chunkComposite.addComponent(chunk); + chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); + } + + ctx.writeAndFlush(chunkComposite).addListener(future -> ctx.close()); + + secureChannel.setChannelId(0); + } catch (MessageEncodeException e) { + logger.error("Error encoding {}: {}", request, e.getMessage(), e); + handshakeFuture.completeExceptionally(e); + ctx.close(); + } catch (UaSerializationException e) { + logger.error("Error serializing {}: {}", request, e.getMessage(), e); + handshakeFuture.completeExceptionally(e); + ctx.close(); + } finally { + messageBuffer.release(); + } + } + + private void checkMessageSize(ByteBuf messageBuffer) throws UaSerializationException { + int messageSize = messageBuffer.readableBytes(); + int remoteMaxMessageSize = channelParameters.getRemoteMaxMessageSize(); + + if (remoteMaxMessageSize > 0 && messageSize > remoteMaxMessageSize) { + throw new UaSerializationException( + StatusCodes.Bad_RequestTooLarge, + "request exceeds remote max message size: " + + messageSize + " > " + remoteMaxMessageSize + ); + } + } + + private int getMaxChunkCount() { + return channelParameters.getLocalMaxChunkCount(); + } + + private int getMaxChunkSize() { + return channelParameters.getLocalReceiveBufferSize(); + } + + private static ClientSecureChannel newSecureChannel(ClientApplicationContext application) throws UaException { + EndpointDescription endpoint = application.getEndpoint(); + + SecurityPolicy securityPolicy = SecurityPolicy.fromUri(endpoint.getSecurityPolicyUri()); + + if (securityPolicy == SecurityPolicy.None) { + return new ClientSecureChannel(securityPolicy, endpoint.getSecurityMode()); + } else { + KeyPair keyPair = application.getKeyPair().orElseThrow( + () -> + new UaException(StatusCodes.Bad_ConfigurationError, "no KeyPair configured") + ); + + X509Certificate certificate = application.getCertificate().orElseThrow( + () -> + new UaException(StatusCodes.Bad_ConfigurationError, "no certificate configured") + ); + + List certificateChain = Arrays.asList( + application.getCertificateChain().orElseThrow( + () -> + new UaException(StatusCodes.Bad_ConfigurationError, "no certificate chain configured") + ) + ); + + X509Certificate remoteCertificate = + CertificateUtil.decodeCertificate(endpoint.getServerCertificate().bytes()); + + List remoteCertificateChain = + CertificateUtil.decodeCertificates(endpoint.getServerCertificate().bytes()); + + return new ClientSecureChannel( + keyPair, + certificate, + certificateChain, + remoteCertificate, + remoteCertificateChain, + securityPolicy, + endpoint.getSecurityMode() + ); + } + } + + private static int getMessageLength(ByteBuf buffer, int maxMessageLength) throws UaException { + long messageLength = buffer.getUnsignedIntLE(buffer.readerIndex() + 4); + + if (messageLength <= maxMessageLength) { + return (int) messageLength; + } else { + throw new UaException( + StatusCodes.Bad_TcpMessageTooLarge, + String.format("max message length exceeded (%s > %s)", messageLength, maxMessageLength) + ); + } + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascRequest.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascRequest.java new file mode 100644 index 000000000..c1123491c --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascRequest.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.uasc; + +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; + +public final class UascRequest { + + private final long requestId; + private final UaRequestMessageType requestMessage; + + public UascRequest(long requestId, UaRequestMessageType requestMessage) { + this.requestId = requestId; + this.requestMessage = requestMessage; + } + + public long getRequestId() { + return requestId; + } + + public UaRequestMessageType getRequestMessage() { + return requestMessage; + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascResponse.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascResponse.java new file mode 100644 index 000000000..a9b3e8d22 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascResponse.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.uasc; + +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.jetbrains.annotations.Nullable; + +public final class UascResponse { + + private final long requestId; + private final UaResponseMessageType responseMessage; + private final UaException exception; + + private UascResponse( + long requestId, + @Nullable UaResponseMessageType responseMessage, + @Nullable UaException exception + ) { + + this.requestId = requestId; + this.responseMessage = responseMessage; + this.exception = exception; + + // response can't both succeed and fail, one must be null + assert responseMessage == null || exception == null; + } + + public long getRequestId() { + return requestId; + } + + public @Nullable UaResponseMessageType getResponseMessage() { + return responseMessage; + } + + public @Nullable UaException getException() { + return exception; + } + + public boolean isSuccess() { + return responseMessage != null; + } + + public boolean isFailure() { + return exception != null; + } + + public static UascResponse success(long requestId, UaResponseMessageType responseMessage) { + return new UascResponse(requestId, responseMessage, null); + } + + public static UascResponse failure(long requestId, UaException exception) { + return new UascResponse(requestId, null, exception); + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascResponseHandler.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascResponseHandler.java new file mode 100644 index 000000000..98e2075b8 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascResponseHandler.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.uasc; + +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; + +public interface UascResponseHandler { + + // response successfully received and decoded + void handleResponse(long requestId, UaResponseMessageType responseMessage); + + // failed while sending request + void handleSendFailure(long requestId, UaException exception); + + // failed while decoding response, aborted, decode exception, ServiceFault + void handleReceiveFailure(long requestId, UaException exception); + + void handleChannelError(UaException exception); + + // channel inactive, cancel pending requests? + void handleChannelInactive(); + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/OpcServerTransport.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/OpcServerTransport.java new file mode 100644 index 000000000..808276bfe --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/OpcServerTransport.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server; + +import java.net.InetSocketAddress; + +public interface OpcServerTransport { + + /** + * Bind a {@link ServerApplicationContext} to the given bind address and port. + * + * @param applicationContext the {@link ServerApplicationContext} to bind. + * @param bindAddress the local address to bind to. + * @throws Exception if an error occurs binding to the address/port combination. + */ + void bind(ServerApplicationContext applicationContext, InetSocketAddress bindAddress) throws Exception; + + /** + * Unbind this transport (close the server channel). + * + * @throws Exception if an error occurs unbinding this transport. + */ + void unbind() throws Exception; + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/OpcServerTransportConfig.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/OpcServerTransportConfig.java new file mode 100644 index 000000000..f381643ad --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/OpcServerTransportConfig.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server; + +import java.util.concurrent.ExecutorService; + +import io.netty.channel.EventLoopGroup; + +public interface OpcServerTransportConfig { + + /** + * Get the {@link ExecutorService} to be used by this transport. + * + * @return the {@link ExecutorService} to be used by this transport. + */ + ExecutorService getExecutor(); + + /** + * Get the {@link EventLoopGroup} to be used by this transport. + * + * @return the {@link EventLoopGroup} to be used by this transport. + */ + EventLoopGroup getEventLoop(); + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/OpcServerTransportFactory.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/OpcServerTransportFactory.java new file mode 100644 index 000000000..7662e1efd --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/OpcServerTransportFactory.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server; + +import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; + +public interface OpcServerTransportFactory { + + /** + * Create an {@link OpcServerTransport} instance for a {@link TransportProfile}. + * + * @param transportProfile the {@link TransportProfile}. + * @return a new {@link OpcServerTransport} for the provided {@link TransportProfile}. + */ + OpcServerTransport create(TransportProfile transportProfile); + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServerApplicationContext.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServerApplicationContext.java new file mode 100644 index 000000000..8ef571eb7 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServerApplicationContext.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; +import org.eclipse.milo.opcua.stack.core.security.CertificateManager; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; + +public interface ServerApplicationContext { + + /** + * Get the {@link EndpointDescription}s the server is providing. + * + * @return the {@link EndpointDescription}s the server is providing. + */ + List getEndpointDescriptions(); + + /** + * Get the server's {@link CertificateManager}. + * + * @return the server's {@link CertificateManager}. + */ + CertificateManager getCertificateManager(); + + /** + * Get the server's {@link CertificateValidator}. + * + * @return the server's {@link CertificateValidator}. + */ + CertificateValidator getCertificateValidator(); + + /** + * Get the server's static {@link EncodingContext}. + * + * @return the server's static {@link EncodingContext}. + */ + EncodingContext getEncodingContext(); + + /** + * Get the next unique secure channel id to assign to a secure channel. + * + * @return the next unique secure channel id to assign to a secure channel. + */ + Long getNextSecureChannelId(); + + /** + * Get the next unique secure channel token id to assign when a secure channel is renewed. + * + * @return the next unique secure channel token id to assign when a secure channel is renewed. + */ + Long getNextSecureChannelTokenId(); + + /** + * Handle an inbound service request, returning a {@link CompletableFuture} that completes + * with the service response. + * + * @param context the {@link ServiceRequestContext}. + * @param requestMessage the {@link UaRequestMessageType} to handle. + * @return a {@link CompletableFuture} that completes successfully with the service result, or + * completes exceptionally if there was a service fault. + */ + CompletableFuture handleServiceRequest( + ServiceRequestContext context, + UaRequestMessageType requestMessage + ); + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServiceRequest.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServiceRequest.java new file mode 100644 index 000000000..4a068c947 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServiceRequest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server; + +import io.netty.channel.Channel; +import org.eclipse.milo.opcua.stack.core.channel.SecureChannel; +import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; + +/** + * Holds a received {@link UaRequestMessageType} with some additional transport layer details. + */ +public class ServiceRequest implements ServiceRequestContext { + + private final long receivedAtNanos = System.nanoTime(); + + private final String endpointUrl; + private final TransportProfile transportProfile; + private final Channel channel; + private final SecureChannel secureChannel; + private final UaRequestMessageType requestMessage; + + public ServiceRequest( + String endpointUrl, + TransportProfile transportProfile, + Channel channel, + SecureChannel secureChannel, + UaRequestMessageType requestMessage + ) { + + this.endpointUrl = endpointUrl; + this.transportProfile = transportProfile; + this.channel = channel; + this.secureChannel = secureChannel; + this.requestMessage = requestMessage; + } + + @Override + public String getEndpointUrl() { + return endpointUrl; + } + + @Override + public TransportProfile getTransportProfile() { + return transportProfile; + } + + @Override + public Channel getChannel() { + return channel; + } + + @Override + public SecureChannel getSecureChannel() { + return secureChannel; + } + + @Override + public Long receivedAtNanos() { + return receivedAtNanos; + } + + /** + * Get the incoming {@link UaRequestMessageType}. + * + * @return the incoming {@link UaRequestMessageType}. + */ + public UaRequestMessageType getRequestMessage() { + return requestMessage; + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServiceRequestContext.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServiceRequestContext.java new file mode 100644 index 000000000..738d408c7 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServiceRequestContext.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server; + + +import java.net.InetAddress; +import java.net.InetSocketAddress; + +import io.netty.channel.Channel; +import org.eclipse.milo.opcua.stack.core.channel.SecureChannel; +import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; + +/** + * Transport layer details that accompany an inbound {@link UaRequestMessageType}. + */ +public interface ServiceRequestContext { + + /** + * Get the endpoint URL of the endpoint the client that originated the request is + * connected to. + * + * @return the endpoint URL of the endpoint the client that originated the request is + * connected to. + */ + String getEndpointUrl(); + + /** + * Get the {@link TransportProfile} of the transport the client that originated the + * request used to connect. + * + * @return the {@link TransportProfile} of the transport the client that originated the + * request used to connect. + */ + TransportProfile getTransportProfile(); + + /** + * Get the Netty {@link Channel} the request originated from. + * + * @return the Netty {@link Channel} the request originated from. + */ + Channel getChannel(); + + /** + * Get the {@link SecureChannel} the request originated from. + * + * @return the {@link SecureChannel} the request originated from. + */ + SecureChannel getSecureChannel(); + + /** + * Get the system time, in nanos, that this request was received at. + * + * @return the system time, in nanos, that this request was received at. + * @see System#nanoTime() + */ + Long receivedAtNanos(); + + /** + * Get the {@link InetAddress} of the client that originated the request. + * + * @return the {@link InetAddress} of the client that originated the request. + */ + default InetAddress clientAddress() { + return ((InetSocketAddress) getChannel().remoteAddress()).getAddress(); + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServiceResponse.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServiceResponse.java new file mode 100644 index 000000000..09ec62d4c --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServiceResponse.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server; + +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; + +public class ServiceResponse { + + private final UaResponseMessageType responseMessage; + + public ServiceResponse(UaResponseMessageType responseMessage) { + this.responseMessage = responseMessage; + } + + public UaResponseMessageType getResponseMessage() { + return responseMessage; + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/OpcTcpServerTransport.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/OpcTcpServerTransport.java new file mode 100644 index 000000000..f7212c203 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/OpcTcpServerTransport.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server.tcp; + +import java.net.InetSocketAddress; +import java.util.HashSet; +import java.util.Set; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LoggingHandler; +import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +import org.eclipse.milo.opcua.stack.core.util.Lazy; +import org.eclipse.milo.opcua.stack.transport.server.OpcServerTransport; +import org.eclipse.milo.opcua.stack.transport.server.ServerApplicationContext; +import org.eclipse.milo.opcua.stack.transport.server.uasc.UascServerHelloHandler; + +public class OpcTcpServerTransport implements OpcServerTransport { + + private final Set boundAddresses = new HashSet<>(); + private final Set channelReferences = new HashSet<>(); + private final Lazy serverBootstrap = new Lazy<>(); + + private final OpcTcpServerTransportConfig config; + + public OpcTcpServerTransport(OpcTcpServerTransportConfig config) { + this.config = config; + } + + @Override + public synchronized void bind(ServerApplicationContext applicationContext, InetSocketAddress bindAddress) throws Exception { + ServerBootstrap bootstrap = serverBootstrap.getOrCompute(() -> + new ServerBootstrap() + .channel(NioServerSocketChannel.class) + .group(config.getEventLoop()) + .handler(new LoggingHandler(OpcTcpServerTransport.class)) + .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .childOption(ChannelOption.TCP_NODELAY, true) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel channel) { + channel.pipeline().addLast(RateLimitingHandler.getInstance()); + channel.pipeline().addLast( + new UascServerHelloHandler(config, applicationContext, TransportProfile.TCP_UASC_UABINARY) + ); + } + }) + ); + + assert bootstrap != null; + + if (!boundAddresses.contains(bindAddress)) { + ChannelFuture bindFuture = bootstrap.bind(bindAddress).sync(); + + boundAddresses.add(bindAddress); + channelReferences.add(bindFuture.channel()); + } + } + + @Override + public synchronized void unbind() { + boundAddresses.clear(); + + channelReferences.forEach(channel -> { + try { + channel.close().sync(); + } catch (InterruptedException ignored) { + } + }); + channelReferences.clear(); + + serverBootstrap.reset(); + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/OpcTcpServerTransportConfig.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/OpcTcpServerTransportConfig.java new file mode 100644 index 000000000..03edcd27b --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/OpcTcpServerTransportConfig.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server.tcp; + +import org.eclipse.milo.opcua.stack.transport.server.OpcServerTransportConfig; +import org.eclipse.milo.opcua.stack.transport.server.uasc.UascServerConfig; + +public interface OpcTcpServerTransportConfig extends OpcServerTransportConfig, UascServerConfig { + + /** + * Create a new {@link OpcTcpServerTransportConfigBuilder}. + * + * @return a new {@link OpcTcpServerTransportConfigBuilder}. + */ + static OpcTcpServerTransportConfigBuilder newBuilder() { + return new OpcTcpServerTransportConfigBuilder(); + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/OpcTcpServerTransportConfigBuilder.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/OpcTcpServerTransportConfigBuilder.java new file mode 100644 index 000000000..bcb401577 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/OpcTcpServerTransportConfigBuilder.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server.tcp; + +import java.util.concurrent.ExecutorService; + +import io.netty.channel.EventLoopGroup; +import org.eclipse.milo.opcua.stack.core.Stack; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; + +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; + +public class OpcTcpServerTransportConfigBuilder { + + private ExecutorService executor; + private EventLoopGroup eventLoop; + private UInteger helloDeadline = uint(10_000); + private UInteger minimumSecureChannelLifetime = uint(60_000); + private UInteger maximumSecureChannelLifetime = uint(60_000 * 60 * 24); + + public OpcTcpServerTransportConfigBuilder setExecutor(ExecutorService executor) { + this.executor = executor; + return this; + } + + public OpcTcpServerTransportConfigBuilder setEventLoop(EventLoopGroup eventLoop) { + this.eventLoop = eventLoop; + return this; + } + + public OpcTcpServerTransportConfigBuilder setHelloDeadline(UInteger helloDeadline) { + this.helloDeadline = helloDeadline; + return this; + } + + public OpcTcpServerTransportConfigBuilder setMinimumSecureChannelLifetime(UInteger minimumSecureChannelLifetime) { + this.minimumSecureChannelLifetime = minimumSecureChannelLifetime; + return this; + } + + public OpcTcpServerTransportConfigBuilder setMaximumSecureChannelLifetime(UInteger maximumSecureChannelLifetime) { + this.maximumSecureChannelLifetime = maximumSecureChannelLifetime; + return this; + } + + public OpcTcpServerTransportConfig build() { + if (executor == null) { + executor = Stack.sharedExecutor(); + } + if (eventLoop == null) { + eventLoop = Stack.sharedEventLoop(); + } + + return new OpcTcpServerTransportConfigImpl( + executor, + eventLoop, + helloDeadline, + minimumSecureChannelLifetime, + maximumSecureChannelLifetime + ); + } + + static class OpcTcpServerTransportConfigImpl implements OpcTcpServerTransportConfig { + + private final ExecutorService executor; + private final EventLoopGroup eventLoop; + private final UInteger helloDeadline; + private final UInteger minimumSecureChannelLifetime; + private final UInteger maximumSecureChannelLifetime; + + public OpcTcpServerTransportConfigImpl( + ExecutorService executor, + EventLoopGroup eventLoop, + UInteger helloDeadline, + UInteger minimumSecureChannelLifetime, + UInteger maximumSecureChannelLifetime + ) { + + this.executor = executor; + this.eventLoop = eventLoop; + this.helloDeadline = helloDeadline; + this.minimumSecureChannelLifetime = minimumSecureChannelLifetime; + this.maximumSecureChannelLifetime = maximumSecureChannelLifetime; + } + + @Override + public ExecutorService getExecutor() { + return executor; + } + + @Override + public EventLoopGroup getEventLoop() { + return eventLoop; + } + + @Override + public UInteger getHelloDeadline() { + return helloDeadline; + } + + @Override + public UInteger getMinimumSecureChannelLifetime() { + return minimumSecureChannelLifetime; + } + + @Override + public UInteger getMaximumSecureChannelLifetime() { + return maximumSecureChannelLifetime; + } + + } + +} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/RateLimitingHandler.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/RateLimitingHandler.java similarity index 96% rename from opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/RateLimitingHandler.java rename to opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/RateLimitingHandler.java index ff693302a..aba2fe3e7 100644 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/RateLimitingHandler.java +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/tcp/RateLimitingHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 the Eclipse Milo Authors + * Copyright (c) 2022 the Eclipse Milo Authors * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.server.transport; +package org.eclipse.milo.opcua.stack.transport.server.tcp; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -25,7 +25,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.ipfilter.AbstractRemoteAddressFilter; import org.eclipse.milo.opcua.stack.core.Stack; -import org.eclipse.milo.opcua.stack.server.UaStackServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +32,7 @@ * A shared, stack-wide, one-per-application-regardless-of-how-many-server-instances-you-have handler that is added to * the beginning of every server pipeline to handle rate limiting and connection limits. *

- * Any configuration changes must be made before {@link UaStackServer#startup()} is called for the first time, + * Any configuration changes must be made before an {@link OpcTcpServerTransport} is bound the first time, * application-wide. Once the instance has been created further configuration changes will have no effect. */ @ChannelHandler.Sharable diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/uasc/UascServerAsymmetricHandler.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerAsymmetricHandler.java similarity index 72% rename from opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/uasc/UascServerAsymmetricHandler.java rename to opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerAsymmetricHandler.java index d1bf39b74..7d7a42383 100644 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/uasc/UascServerAsymmetricHandler.java +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerAsymmetricHandler.java @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.server.transport.uasc; +package org.eclipse.milo.opcua.stack.transport.server.uasc; import java.io.IOException; import java.security.KeyPair; @@ -31,20 +31,23 @@ import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.UaSerializationException; +import org.eclipse.milo.opcua.stack.core.channel.ChannelParameters; import org.eclipse.milo.opcua.stack.core.channel.ChannelSecurity; import org.eclipse.milo.opcua.stack.core.channel.ChannelSecurity.SecurityKeys; import org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder; +import org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder; import org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder.EncodedMessage; import org.eclipse.milo.opcua.stack.core.channel.ExceptionHandler; import org.eclipse.milo.opcua.stack.core.channel.MessageAbortException; import org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException; import org.eclipse.milo.opcua.stack.core.channel.MessageEncodeException; -import org.eclipse.milo.opcua.stack.core.channel.SerializationQueue; import org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel; import org.eclipse.milo.opcua.stack.core.channel.headers.AsymmetricSecurityHeader; import org.eclipse.milo.opcua.stack.core.channel.headers.HeaderDecoder; import org.eclipse.milo.opcua.stack.core.channel.messages.ErrorMessage; import org.eclipse.milo.opcua.stack.core.channel.messages.MessageType; +import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryDecoder; +import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryEncoder; import org.eclipse.milo.opcua.stack.core.security.CertificateManager; import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; @@ -61,7 +64,7 @@ import org.eclipse.milo.opcua.stack.core.util.BufferUtil; import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; import org.eclipse.milo.opcua.stack.core.util.NonceUtil; -import org.eclipse.milo.opcua.stack.server.UaStackServer; +import org.eclipse.milo.opcua.stack.transport.server.ServerApplicationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -83,25 +86,72 @@ public class UascServerAsymmetricHandler extends ByteToMessageDecoder implements private final AtomicReference headerRef = new AtomicReference<>(); + private final OpcUaBinaryEncoder binaryEncoder; + private final OpcUaBinaryDecoder binaryDecoder; + private final ChunkEncoder chunkEncoder; + private final ChunkDecoder chunkDecoder; + private final int maxChunkCount; private final int maxChunkSize; - private final UaStackServer stackServer; + private final UascServerConfig config; + private final ServerApplicationContext application; private final TransportProfile transportProfile; - private final SerializationQueue serializationQueue; + private final ChannelParameters channelParameters; UascServerAsymmetricHandler( - UaStackServer stackServer, + UascServerConfig config, + ServerApplicationContext application, TransportProfile transportProfile, - SerializationQueue serializationQueue + ChannelParameters channelParameters ) { - this.stackServer = stackServer; + this.config = config; + this.application = application; this.transportProfile = transportProfile; - this.serializationQueue = serializationQueue; + this.channelParameters = channelParameters; + + binaryEncoder = new OpcUaBinaryEncoder(application.getEncodingContext()); + binaryDecoder = new OpcUaBinaryDecoder(application.getEncodingContext()); + + chunkEncoder = new ChunkEncoder(channelParameters); + chunkDecoder = new ChunkDecoder(channelParameters, application.getEncodingContext().getEncodingLimits()); + + maxChunkCount = channelParameters.getLocalMaxChunkCount(); + maxChunkSize = channelParameters.getLocalReceiveBufferSize(); + } + + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (secureChannelTimeout != null) { + secureChannelTimeout.cancel(); + secureChannelTimeout = null; + } + + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + chunkBuffers.forEach(ReferenceCountUtil::safeRelease); + chunkBuffers.clear(); + + if (cause instanceof IOException) { + ctx.close(); + logger.debug("[remote={}] IOException caught; channel closed", + ctx.channel().remoteAddress(), cause); + } else { + ErrorMessage errorMessage = ExceptionHandler.sendErrorMessage(ctx, cause); - maxChunkCount = serializationQueue.getParameters().getLocalMaxChunkCount(); - maxChunkSize = serializationQueue.getParameters().getLocalReceiveBufferSize(); + if (cause instanceof UaException) { + logger.debug("[remote={}] UaException caught; sent {}", + ctx.channel().remoteAddress(), errorMessage, cause); + } else { + logger.error("[remote={}] Exception caught; sent {}", + ctx.channel().remoteAddress(), errorMessage, cause); + } + } } @Override @@ -158,7 +208,7 @@ private void onOpenSecureChannel(ChannelHandlerContext ctx, ByteBuf buffer) thro final AsymmetricSecurityHeader header = AsymmetricSecurityHeader.decode( buffer, - stackServer.getConfig().getEncodingLimits() + application.getEncodingContext().getEncodingLimits() ); if (!headerRef.compareAndSet(null, header)) { @@ -182,7 +232,7 @@ private void onOpenSecureChannel(ChannelHandlerContext ctx, ByteBuf buffer) thro if (secureChannel == null) { secureChannel = new ServerSecureChannel(); - secureChannel.setChannelId(stackServer.getNextChannelId()); + secureChannel.setChannelId(application.getNextSecureChannelId()); String securityPolicyUri = header.getSecurityPolicyUri(); SecurityPolicy securityPolicy = SecurityPolicy.fromUri(securityPolicyUri); @@ -192,11 +242,11 @@ private void onOpenSecureChannel(ChannelHandlerContext ctx, ByteBuf buffer) thro if (securityPolicy != SecurityPolicy.None) { secureChannel.setRemoteCertificate(header.getSenderCertificate().bytesOrEmpty()); - CertificateValidator certificateValidator = stackServer.getConfig().getCertificateValidator(); + CertificateValidator certificateValidator = application.getCertificateValidator(); certificateValidator.validateCertificateChain(secureChannel.getRemoteCertificateChain()); - CertificateManager certificateManager = stackServer.getConfig().getCertificateManager(); + CertificateManager certificateManager = application.getCertificateManager(); Optional localCertificateChain = certificateManager .getCertificateChain(header.getReceiverThumbprint()); @@ -238,49 +288,47 @@ private void onOpenSecureChannel(ChannelHandlerContext ctx, ByteBuf buffer) thro chunkBuffers = new ArrayList<>(); headerRef.set(null); - serializationQueue.decode((binaryDecoder, chunkDecoder) -> { - ByteBuf message; - long requestId; + ByteBuf message; + long requestId; - try { - ChunkDecoder.DecodedMessage decodedMessage = - chunkDecoder.decodeAsymmetric(secureChannel, buffersToDecode); + try { + ChunkDecoder.DecodedMessage decodedMessage = + chunkDecoder.decodeAsymmetric(secureChannel, buffersToDecode); - message = decodedMessage.getMessage(); - requestId = decodedMessage.getRequestId(); - } catch (MessageAbortException e) { - logger.warn( - "Received message abort chunk; error={}, reason={}", - e.getStatusCode(), e.getMessage() - ); - return; - } catch (MessageDecodeException e) { - logger.error("Error decoding asymmetric message", e); + message = decodedMessage.getMessage(); + requestId = decodedMessage.getRequestId(); + } catch (MessageAbortException e) { + logger.warn( + "Received message abort chunk; error={}, reason={}", + e.getStatusCode(), e.getMessage() + ); + return; + } catch (MessageDecodeException e) { + logger.error("Error decoding asymmetric message", e); - ctx.close(); - return; - } + ctx.close(); + return; + } - try { - OpenSecureChannelRequest request = (OpenSecureChannelRequest) binaryDecoder - .setBuffer(message) - .decodeMessage(null); + try { + OpenSecureChannelRequest request = (OpenSecureChannelRequest) binaryDecoder + .setBuffer(message) + .decodeMessage(null); - logger.debug( - "Received OpenSecureChannelRequest ({}, id={}).", - request.getRequestType(), secureChannelId - ); + logger.debug( + "Received OpenSecureChannelRequest ({}, id={}).", + request.getRequestType(), secureChannelId + ); - sendOpenSecureChannelResponse(ctx, requestId, request); - } catch (Throwable t) { - logger.error("Error decoding OpenSecureChannelRequest", t); + sendOpenSecureChannelResponse(ctx, requestId, request); + } catch (Throwable t) { + logger.error("Error decoding OpenSecureChannelRequest", t); - ctx.close(); - } finally { - message.release(); - buffersToDecode.clear(); - } - }); + ctx.close(); + } finally { + message.release(); + buffersToDecode.clear(); + } } } } @@ -291,59 +339,61 @@ private void sendOpenSecureChannelResponse( OpenSecureChannelRequest request ) { - serializationQueue.encode((binaryEncoder, chunkEncoder) -> { - ByteBuf messageBuffer = BufferUtil.pooledBuffer(); - - try { - OpenSecureChannelResponse response = openSecureChannel(ctx, request); + ByteBuf messageBuffer = BufferUtil.pooledBuffer(); - binaryEncoder.setBuffer(messageBuffer); - binaryEncoder.encodeMessage(null, response); + try { + OpenSecureChannelResponse response = openSecureChannel(ctx, request); - checkMessageSize(messageBuffer); + binaryEncoder.setBuffer(messageBuffer); + binaryEncoder.encodeMessage(null, response); - EncodedMessage encodedMessage = chunkEncoder.encodeAsymmetric( - secureChannel, - requestId, - messageBuffer, - MessageType.OpenSecureChannel - ); + checkMessageSize(messageBuffer); - if (!symmetricHandlerAdded) { - UascServerSymmetricHandler symmetricHandler = new UascServerSymmetricHandler( - stackServer, - serializationQueue, - secureChannel - ); + EncodedMessage encodedMessage = chunkEncoder.encodeAsymmetric( + secureChannel, + requestId, + messageBuffer, + MessageType.OpenSecureChannel + ); - ctx.pipeline().addBefore(ctx.name(), null, symmetricHandler); + if (!symmetricHandlerAdded) { + var symmetricHandler = new UascServerSymmetricHandler( + config, + application, + transportProfile, + channelParameters, + chunkEncoder, + chunkDecoder, + secureChannel + ); - symmetricHandlerAdded = true; - } + ctx.pipeline().addBefore(ctx.name(), null, symmetricHandler); - CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); + symmetricHandlerAdded = true; + } - for (ByteBuf chunk : encodedMessage.getMessageChunks()) { - chunkComposite.addComponent(chunk); - chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); - } + CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); - ctx.writeAndFlush(chunkComposite, ctx.voidPromise()); - - logger.debug("Sent OpenSecureChannelResponse."); - } catch (MessageEncodeException e) { - logger.error("Error encoding OpenSecureChannelResponse: {}", e.getMessage(), e); - ctx.fireExceptionCaught(e); - } catch (UaSerializationException e) { - logger.error("Error serializing OpenSecureChannelResponse: {}", e.getMessage(), e); - ctx.fireExceptionCaught(e); - } catch (UaException e) { - logger.error("Error installing security token: {}", e.getStatusCode(), e); - ctx.close(); - } finally { - messageBuffer.release(); + for (ByteBuf chunk : encodedMessage.getMessageChunks()) { + chunkComposite.addComponent(chunk); + chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); } - }); + + ctx.writeAndFlush(chunkComposite, ctx.voidPromise()); + + logger.debug("Sent OpenSecureChannelResponse."); + } catch (MessageEncodeException e) { + logger.error("Error encoding OpenSecureChannelResponse: {}", e.getMessage(), e); + ctx.fireExceptionCaught(e); + } catch (UaSerializationException e) { + logger.error("Error serializing OpenSecureChannelResponse: {}", e.getMessage(), e); + ctx.fireExceptionCaught(e); + } catch (UaException e) { + logger.error("Error installing security token: {}", e.getStatusCode(), e); + ctx.close(); + } finally { + messageBuffer.release(); + } } private OpenSecureChannelResponse openSecureChannel( @@ -358,7 +408,7 @@ private OpenSecureChannelResponse openSecureChannel( String endpointUrl = ctx.channel().attr(UascServerHelloHandler.ENDPOINT_URL_KEY).get(); - EndpointDescription endpoint = stackServer.getEndpointDescriptions() + EndpointDescription endpoint = application.getEndpointDescriptions() .stream() .filter(e -> { boolean transportMatch = Objects.equals( @@ -381,7 +431,12 @@ private OpenSecureChannelResponse openSecureChannel( request.getSecurityMode() ); - return transportMatch && pathMatch && securityPolicyMatch && securityModeMatch; + // allow a matched endpoint OR any unsecured connection, regardless of the + // endpoint security, so that the receiving ServerApplication can decide if + // it wants to allow unsecured Discovery services. + return transportMatch && pathMatch && + (securityPolicyMatch && securityModeMatch || + secureChannel.getSecurityPolicy() == SecurityPolicy.None); }) .findFirst() .orElseThrow(() -> { @@ -411,16 +466,16 @@ private OpenSecureChannelResponse openSecureChannel( channelLifetime = Math.min( channelLifetime, - stackServer.getConfig().getMaximumSecureChannelLifetime().longValue() + config.getMaximumSecureChannelLifetime().longValue() ); channelLifetime = Math.max( channelLifetime, - stackServer.getConfig().getMinimumSecureChannelLifetime().longValue() + config.getMinimumSecureChannelLifetime().longValue() ); ChannelSecurityToken newToken = new ChannelSecurityToken( uint(secureChannel.getChannelId()), - uint(stackServer.getNextTokenId()), + uint(application.getNextSecureChannelTokenId()), DateTime.now(), uint(channelLifetime) ); @@ -494,46 +549,15 @@ private OpenSecureChannelResponse openSecureChannel( private void checkMessageSize(ByteBuf messageBuffer) throws UaSerializationException { int messageSize = messageBuffer.readableBytes(); - int remoteMaxMessageSize = serializationQueue.getParameters().getRemoteMaxMessageSize(); + int remoteMaxMessageSize = channelParameters.getRemoteMaxMessageSize(); if (remoteMaxMessageSize > 0 && messageSize > remoteMaxMessageSize) { throw new UaSerializationException( StatusCodes.Bad_ResponseTooLarge, "response exceeds remote max message size: " + - messageSize + " > " + remoteMaxMessageSize); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - chunkBuffers.forEach(ReferenceCountUtil::safeRelease); - chunkBuffers.clear(); - - if (cause instanceof IOException) { - ctx.close(); - logger.debug("[remote={}] IOException caught; channel closed", - ctx.channel().remoteAddress(), cause); - } else { - ErrorMessage errorMessage = ExceptionHandler.sendErrorMessage(ctx, cause); - - if (cause instanceof UaException) { - logger.debug("[remote={}] UaException caught; sent {}", - ctx.channel().remoteAddress(), errorMessage, cause); - } else { - logger.error("[remote={}] Exception caught; sent {}", - ctx.channel().remoteAddress(), errorMessage, cause); - } - } - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - if (secureChannelTimeout != null) { - secureChannelTimeout.cancel(); - secureChannelTimeout = null; + messageSize + " > " + remoteMaxMessageSize + ); } - - super.channelInactive(ctx); } } diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerConfig.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerConfig.java new file mode 100644 index 000000000..fc320e34a --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerConfig.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server.uasc; + +import java.util.concurrent.ExecutorService; + +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; + +public interface UascServerConfig { + + /** + * Get the {@link ExecutorService} to use when dispatching inbound {@link UascServiceRequest}s + * that arrive while on the Netty event loop thread. + * + * @return the {@link ExecutorService} to use when dispatching inbound + * {@link UascServiceRequest}s. + */ + ExecutorService getExecutor(); + + /** + * Get the deadline, in milliseconds, that a "Hello" message must arrive by after the + * underlying channel is activated. + * + * @return the "Hello" message deadline, in milliseconds. + */ + UInteger getHelloDeadline(); + + /** + * Get the minimum allowed secure channel lifetime, in milliseconds. Requested lifetimes + * smaller than this value will be revised to this value. + * + * @return the minimum allowed secure channel lifetime, in milliseconds. + */ + UInteger getMinimumSecureChannelLifetime(); + + /** + * Get the maximum allowed secure channel lifetime, in milliseconds. Requested lifetimes + * larger than this value will be revised to this value. + * + * @return the maximum allowed secure channel lifetime, in milliseconds. + */ + UInteger getMaximumSecureChannelLifetime(); + +} diff --git a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/uasc/UascServerHelloHandler.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerHelloHandler.java similarity index 87% rename from opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/uasc/UascServerHelloHandler.java rename to opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerHelloHandler.java index 72d2a3106..0fc13c23b 100644 --- a/opc-ua-stack/stack-server/src/main/java/org/eclipse/milo/opcua/stack/server/transport/uasc/UascServerHelloHandler.java +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerHelloHandler.java @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.milo.opcua.stack.server.transport.uasc; +package org.eclipse.milo.opcua.stack.transport.server.uasc; import java.io.IOException; import java.util.List; @@ -21,13 +21,11 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.util.AttributeKey; -import org.eclipse.milo.opcua.stack.core.Stack; import org.eclipse.milo.opcua.stack.core.StatusCodes; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.channel.ChannelParameters; import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; import org.eclipse.milo.opcua.stack.core.channel.ExceptionHandler; -import org.eclipse.milo.opcua.stack.core.channel.SerializationQueue; import org.eclipse.milo.opcua.stack.core.channel.headers.HeaderDecoder; import org.eclipse.milo.opcua.stack.core.channel.messages.AcknowledgeMessage; import org.eclipse.milo.opcua.stack.core.channel.messages.ErrorMessage; @@ -37,7 +35,7 @@ import org.eclipse.milo.opcua.stack.core.channel.messages.TcpMessageEncoder; import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; import org.eclipse.milo.opcua.stack.core.util.EndpointUtil; -import org.eclipse.milo.opcua.stack.server.UaStackServer; +import org.eclipse.milo.opcua.stack.transport.server.ServerApplicationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,23 +55,30 @@ public class UascServerHelloHandler extends ByteToMessageDecoder implements Head private volatile boolean receivedHello = false; - private final UaStackServer stackServer; + private final UascServerConfig config; + private final ServerApplicationContext application; private final TransportProfile transportProfile; - public UascServerHelloHandler(UaStackServer stackServer, TransportProfile transportProfile) { + public UascServerHelloHandler( + UascServerConfig config, + ServerApplicationContext application, + TransportProfile transportProfile + ) { + if (transportProfile != TransportProfile.TCP_UASC_UABINARY && transportProfile != TransportProfile.WSS_UASC_UABINARY) { throw new IllegalArgumentException("transportProfile: " + transportProfile); } - this.stackServer = stackServer; + this.config = config; + this.application = application; this.transportProfile = transportProfile; } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { - int helloDeadlineMs = Stack.ConnectionLimits.HELLO_DEADLINE_MS; + int helloDeadlineMs = config.getHelloDeadline().intValue(); logger.debug("Scheduling Hello deadline for +" + helloDeadlineMs + "ms"); @@ -96,6 +101,26 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { super.channelActive(ctx); } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + if (cause instanceof IOException) { + ctx.close(); + logger.debug("[remote={}] IOException caught; channel closed", + ctx.channel().remoteAddress(), cause); + } else { + ErrorMessage errorMessage = ExceptionHandler.sendErrorMessage(ctx, cause); + + if (cause instanceof UaException) { + logger.debug("[remote={}] UaException caught; sent {}", + ctx.channel().remoteAddress(), errorMessage, cause); + } else { + logger.error("[remote={}] Exception caught; sent {}", + ctx.channel().remoteAddress(), errorMessage, cause); + } + } + } + @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { if (buffer.readableBytes() >= HEADER_LENGTH) { @@ -128,7 +153,7 @@ private void onHello(ChannelHandlerContext ctx, ByteBuf buffer) throws UaExcepti String endpointUrl = hello.getEndpointUrl(); boolean endpointMatch = endpointUrl != null && - stackServer.getEndpointDescriptions() + application.getEndpointDescriptions() .stream() .anyMatch(endpoint -> Objects.equals( @@ -155,21 +180,21 @@ private void onHello(ChannelHandlerContext ctx, ByteBuf buffer) throws UaExcepti "unsupported protocol version: " + remoteProtocolVersion); } - EncodingLimits config = stackServer.getConfig().getEncodingLimits(); + EncodingLimits encodingLimits = application.getEncodingContext().getEncodingLimits(); /* Our receive buffer size is determined by the remote send buffer size. */ - long localReceiveBufferSize = Math.min(remoteSendBufferSize, config.getMaxChunkSize()); + long localReceiveBufferSize = Math.min(remoteSendBufferSize, encodingLimits.getMaxChunkSize()); /* Our send buffer size is determined by the remote receive buffer size. */ - long localSendBufferSize = Math.min(remoteReceiveBufferSize, config.getMaxChunkSize()); + long localSendBufferSize = Math.min(remoteReceiveBufferSize, encodingLimits.getMaxChunkSize()); /* Max chunk count the remote can send us; not influenced by remote configuration. */ - long localMaxChunkCount = config.getMaxChunkCount(); + long localMaxChunkCount = encodingLimits.getMaxChunkCount(); /* Max message size the remote can send us. Determined by our max chunk count and receive buffer size. */ - long localMaxMessageSize = Math.min(localReceiveBufferSize * localMaxChunkCount, config.getMaxMessageSize()); + long localMaxMessageSize = Math.min(localReceiveBufferSize * localMaxChunkCount, encodingLimits.getMaxMessageSize()); - ChannelParameters parameters = new ChannelParameters( + var channelParameters = new ChannelParameters( Ints.saturatedCast(localMaxMessageSize), Ints.saturatedCast(localReceiveBufferSize), Ints.saturatedCast(localSendBufferSize), @@ -180,13 +205,14 @@ private void onHello(ChannelHandlerContext ctx, ByteBuf buffer) throws UaExcepti Ints.saturatedCast(remoteMaxChunkCount) ); - SerializationQueue serializationQueue = new SerializationQueue( - stackServer.getConfig().getExecutor(), - parameters, - stackServer.getEncodingContext() + var asymmetricHandler = new UascServerAsymmetricHandler( + config, + application, + transportProfile, + channelParameters ); - ctx.pipeline().addLast(new UascServerAsymmetricHandler(stackServer, transportProfile, serializationQueue)); + ctx.pipeline().addLast(asymmetricHandler); ctx.pipeline().remove(this); logger.debug("[remote={}] Removed HelloHandler, added AsymmetricHandler.", ctx.channel().remoteAddress()); @@ -208,23 +234,4 @@ private void onHello(ChannelHandlerContext ctx, ByteBuf buffer) throws UaExcepti logger.debug("[remote={}] Sent Acknowledge message.", ctx.channel().remoteAddress()); } - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (cause instanceof IOException) { - ctx.close(); - logger.debug("[remote={}] IOException caught; channel closed", - ctx.channel().remoteAddress(), cause); - } else { - ErrorMessage errorMessage = ExceptionHandler.sendErrorMessage(ctx, cause); - - if (cause instanceof UaException) { - logger.debug("[remote={}] UaException caught; sent {}", - ctx.channel().remoteAddress(), errorMessage, cause); - } else { - logger.error("[remote={}] Exception caught; sent {}", - ctx.channel().remoteAddress(), errorMessage, cause); - } - } - } - } diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerSymmetricHandler.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerSymmetricHandler.java new file mode 100644 index 000000000..5e91e9a1f --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerSymmetricHandler.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server.uasc; + +import java.util.ArrayList; +import java.util.List; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.CompositeByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageCodec; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.UaSerializationException; +import org.eclipse.milo.opcua.stack.core.channel.ChannelParameters; +import org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder; +import org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder.DecodedMessage; +import org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder; +import org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder.EncodedMessage; +import org.eclipse.milo.opcua.stack.core.channel.MessageAbortException; +import org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException; +import org.eclipse.milo.opcua.stack.core.channel.MessageEncodeException; +import org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel; +import org.eclipse.milo.opcua.stack.core.channel.headers.HeaderDecoder; +import org.eclipse.milo.opcua.stack.core.channel.messages.ErrorMessage; +import org.eclipse.milo.opcua.stack.core.channel.messages.MessageType; +import org.eclipse.milo.opcua.stack.core.channel.messages.TcpMessageEncoder; +import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryDecoder; +import org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaBinaryEncoder; +import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; +import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; +import org.eclipse.milo.opcua.stack.core.util.BufferUtil; +import org.eclipse.milo.opcua.stack.transport.server.ServerApplicationContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UascServerSymmetricHandler extends ByteToMessageCodec implements HeaderDecoder { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final int maxChunkCount; + private final int maxChunkSize; + private List chunkBuffers; + + private final OpcUaBinaryEncoder binaryEncoder; + private final OpcUaBinaryDecoder binaryDecoder; + + private final UascServerConfig config; + private final ServerApplicationContext applicationContext; + private final TransportProfile transportProfile; + private final ChannelParameters channelParameters; + private final ChunkEncoder chunkEncoder; + private final ChunkDecoder chunkDecoder; + private final ServerSecureChannel secureChannel; + + UascServerSymmetricHandler( + UascServerConfig config, + ServerApplicationContext applicationContext, + TransportProfile transportProfile, + ChannelParameters channelParameters, + ChunkEncoder chunkEncoder, + ChunkDecoder chunkDecoder, + ServerSecureChannel secureChannel + ) { + + this.config = config; + this.applicationContext = applicationContext; + this.transportProfile = transportProfile; + this.channelParameters = channelParameters; + this.chunkEncoder = chunkEncoder; + this.chunkDecoder = chunkDecoder; + this.secureChannel = secureChannel; + + binaryEncoder = new OpcUaBinaryEncoder(applicationContext.getEncodingContext()); + binaryDecoder = new OpcUaBinaryDecoder(applicationContext.getEncodingContext()); + + maxChunkCount = channelParameters.getLocalMaxChunkCount(); + maxChunkSize = channelParameters.getLocalReceiveBufferSize(); + + chunkBuffers = new ArrayList<>(maxChunkCount); + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + ctx.pipeline().addLast(new UascServiceRequestHandler(config, applicationContext)); + + super.handlerAdded(ctx); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof ErrorMessage) { + // ErrorMessage triggered by ServerApplication + ErrorMessage errorMessage = (ErrorMessage) evt; + ByteBuf messageBuffer = TcpMessageEncoder.encode(errorMessage); + + ctx.writeAndFlush(messageBuffer).addListener(future -> ctx.close()); + } + + super.userEventTriggered(ctx, evt); + } + + @Override + protected void encode(ChannelHandlerContext ctx, UascServiceResponse response, ByteBuf buffer) throws Exception { + sendServiceResponse(response, buffer); + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception { + if (buffer.readableBytes() >= HEADER_LENGTH) { + int messageLength = getMessageLength(buffer, maxChunkSize); + + if (buffer.readableBytes() >= messageLength) { + MessageType messageType = MessageType.fromMediumInt( + buffer.getMediumLE(buffer.readerIndex()) + ); + + if (messageType == MessageType.SecureMessage) { + onSecureMessage(ctx, buffer.readSlice(messageLength), out); + } else { + ctx.fireChannelRead(buffer.readRetainedSlice(messageLength)); + } + } + } + } + + private void onSecureMessage(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws UaException { + buffer.skipBytes(3); // Skip messageType + + char chunkType = (char) buffer.readByte(); + + if (chunkType == 'A') { + chunkBuffers.forEach(ByteBuf::release); + chunkBuffers.clear(); + } else { + buffer.skipBytes(4); // Skip messageSize + + long secureChannelId = buffer.readUnsignedIntLE(); + if (secureChannelId != secureChannel.getChannelId()) { + throw new UaException(StatusCodes.Bad_SecureChannelIdInvalid, + "invalid secure channel id: " + secureChannelId); + } + + int chunkSize = buffer.readerIndex(0).readableBytes(); + if (chunkSize > maxChunkSize) { + throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, + String.format("max chunk size exceeded (%s)", maxChunkSize)); + } + + chunkBuffers.add(buffer.retain()); + + if (maxChunkCount > 0 && chunkBuffers.size() > maxChunkCount) { + throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, + String.format("max chunk count exceeded (%s)", maxChunkCount)); + } + + if (chunkType == 'F') { + final List buffersToDecode = chunkBuffers; + chunkBuffers = new ArrayList<>(); + + ByteBuf message = null; + + try { + DecodedMessage decodedMessage = + chunkDecoder.decodeSymmetric(secureChannel, buffersToDecode); + + message = decodedMessage.getMessage(); + long requestId = decodedMessage.getRequestId(); + + binaryDecoder.setBuffer(message); + UaRequestMessageType requestMessage = (UaRequestMessageType) binaryDecoder.decodeMessage(null); + + String endpointUrl = ctx.channel() + .attr(UascServerHelloHandler.ENDPOINT_URL_KEY) + .get(); + + var serviceRequest = new UascServiceRequest( + endpointUrl, + transportProfile, + ctx.channel(), + secureChannel, + requestMessage, + requestId + ); + + out.add(serviceRequest); + } catch (MessageAbortException e) { + logger.warn( + "Received message abort chunk; error={}, reason={}", + e.getStatusCode(), e.getMessage() + ); + } catch (MessageDecodeException e) { + logger.error("Error decoding symmetric message", e); + + ctx.close(); + } finally { + if (message != null) { + message.release(); + } + buffersToDecode.clear(); + } + } + } + } + + private void sendServiceResponse(UascServiceResponse response, ByteBuf outBuffer) { + ByteBuf messageBuffer = BufferUtil.pooledBuffer(); + CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); + + try { + binaryEncoder.setBuffer(messageBuffer); + binaryEncoder.encodeMessage(null, response.getResponseMessage()); + + checkMessageSize(messageBuffer); + + EncodedMessage encodedMessage = chunkEncoder.encodeSymmetric( + secureChannel, + response.getRequestId(), + messageBuffer, + MessageType.SecureMessage + ); + + + for (ByteBuf chunk : encodedMessage.getMessageChunks()) { + chunkComposite.addComponent(chunk); + chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); + } + + outBuffer.writeBytes(chunkComposite); + } catch (MessageEncodeException e) { + logger.error("Error encoding {}: {}", response, e.getMessage(), e); + + sendServiceFault(response, outBuffer, e); + } catch (UaSerializationException e) { + logger.error("Error serializing response: {}", e.getStatusCode(), e); + + sendServiceFault(response, outBuffer, e); + } catch (Throwable t) { + logger.error("Uncaught error sending service response", t); + + sendServiceFault(response, outBuffer, t); + } finally { + messageBuffer.release(); + chunkComposite.release(); + } + } + + private void sendServiceFault(UascServiceResponse response, ByteBuf outBuffer, Throwable fault) { + StatusCode statusCode = UaException.extract(fault) + .map(UaException::getStatusCode) + .orElse(new StatusCode(StatusCodes.Bad_InternalError)); + + var serviceFault = new ServiceFault( + new ResponseHeader( + DateTime.now(), + response.getResponseMessage().getResponseHeader().getRequestHandle(), + statusCode, + null, null, null + ) + ); + + ByteBuf messageBuffer = BufferUtil.pooledBuffer(); + CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer(); + + try { + binaryEncoder.setBuffer(messageBuffer); + binaryEncoder.encodeMessage(null, serviceFault); + + checkMessageSize(messageBuffer); + + EncodedMessage encodedMessage = chunkEncoder.encodeSymmetric( + secureChannel, + response.getRequestId(), + messageBuffer, + MessageType.SecureMessage + ); + + for (ByteBuf chunk : encodedMessage.getMessageChunks()) { + chunkComposite.addComponent(chunk); + chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes()); + } + + outBuffer.writeBytes(chunkComposite); + } catch (MessageEncodeException e) { + logger.error("Error encoding {}: {}", serviceFault, e.getMessage(), e); + } catch (UaSerializationException e) { + logger.error("Error serializing ServiceFault: {}", e.getStatusCode(), e); + } finally { + messageBuffer.release(); + chunkComposite.release(); + } + } + + private void checkMessageSize(ByteBuf messageBuffer) throws UaSerializationException { + int messageSize = messageBuffer.readableBytes(); + int remoteMaxMessageSize = channelParameters.getRemoteMaxMessageSize(); + + if (remoteMaxMessageSize > 0 && messageSize > remoteMaxMessageSize) { + throw new UaSerializationException( + StatusCodes.Bad_ResponseTooLarge, + "response exceeds remote max message size: " + + messageSize + " > " + remoteMaxMessageSize + ); + } + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServiceRequest.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServiceRequest.java new file mode 100644 index 000000000..e933fda51 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServiceRequest.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server.uasc; + +import io.netty.channel.Channel; +import org.eclipse.milo.opcua.stack.core.channel.SecureChannel; +import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequest; + +public class UascServiceRequest extends ServiceRequest { + + private final long requestId; + + public UascServiceRequest(String endpointUrl, TransportProfile transportProfile, Channel channel, SecureChannel secureChannel, UaRequestMessageType requestMessage, long requestId) { + super(endpointUrl, transportProfile, channel, secureChannel, requestMessage); + + this.requestId = requestId; + } + + public long getRequestId() { + return requestId; + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServiceRequestHandler.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServiceRequestHandler.java new file mode 100644 index 000000000..c488a7352 --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServiceRequestHandler.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server.uasc; + +import java.util.concurrent.CompletableFuture; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.UaException; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo; +import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; +import org.eclipse.milo.opcua.stack.core.types.structured.ResponseHeader; +import org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault; +import org.eclipse.milo.opcua.stack.transport.server.ServerApplicationContext; + +public class UascServiceRequestHandler extends SimpleChannelInboundHandler { + + private final UascServerConfig config; + private final ServerApplicationContext applicationContext; + + public UascServiceRequestHandler(UascServerConfig config, ServerApplicationContext applicationContext) { + this.config = config; + this.applicationContext = applicationContext; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, UascServiceRequest serviceRequest) { + config.getExecutor().execute(() -> dispatchServiceRequest(serviceRequest)); + } + + private void dispatchServiceRequest(UascServiceRequest serviceRequest) { + CompletableFuture future = applicationContext.handleServiceRequest( + serviceRequest, + serviceRequest.getRequestMessage() + ); + + future.whenComplete(((response, ex) -> { + if (response != null) { + var serviceResponse = new UascServiceResponse( + response, + serviceRequest.getRequestId() + ); + + serviceRequest.getChannel().pipeline().writeAndFlush(serviceResponse); + } else { + StatusCode serviceResult = UaException.extractStatusCode(ex) + .orElse(new StatusCode(StatusCodes.Bad_UnexpectedError)); + + var header = new ResponseHeader( + DateTime.now(), + serviceRequest.getRequestMessage().getRequestHeader().getRequestHandle(), + serviceResult, + DiagnosticInfo.NULL_VALUE, + null, + null + ); + + var serviceResponse = new UascServiceResponse( + new ServiceFault(header), + serviceRequest.getRequestId() + ); + + serviceRequest.getChannel().writeAndFlush(serviceResponse); + } + })); + } + +} diff --git a/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServiceResponse.java b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServiceResponse.java new file mode 100644 index 000000000..79125c5fe --- /dev/null +++ b/opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServiceResponse.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.server.uasc; + +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.eclipse.milo.opcua.stack.transport.server.ServiceResponse; + +public class UascServiceResponse extends ServiceResponse { + + private final long requestId; + + public UascServiceResponse(UaResponseMessageType responseMessage, long requestId) { + super(responseMessage); + + this.requestId = requestId; + } + + public long getRequestId() { + return requestId; + } + +} diff --git a/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpTransportTest.java b/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpTransportTest.java new file mode 100644 index 000000000..0a65fb24f --- /dev/null +++ b/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/OpcTcpTransportTest.java @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.tcp; + +import java.net.InetSocketAddress; +import java.security.KeyPair; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Stream; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.eclipse.milo.opcua.stack.core.NamespaceTable; +import org.eclipse.milo.opcua.stack.core.ServerTable; +import org.eclipse.milo.opcua.stack.core.StatusCodes; +import org.eclipse.milo.opcua.stack.core.channel.EncodingLimits; +import org.eclipse.milo.opcua.stack.core.channel.messages.ErrorMessage; +import org.eclipse.milo.opcua.stack.core.encoding.EncodingContext; +import org.eclipse.milo.opcua.stack.core.encoding.EncodingManager; +import org.eclipse.milo.opcua.stack.core.encoding.OpcUaEncodingManager; +import org.eclipse.milo.opcua.stack.core.security.CertificateManager; +import org.eclipse.milo.opcua.stack.core.security.CertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.ClientCertificateValidator; +import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy; +import org.eclipse.milo.opcua.stack.core.transport.TransportProfile; +import org.eclipse.milo.opcua.stack.core.types.DataTypeManager; +import org.eclipse.milo.opcua.stack.core.types.OpcUaDataTypeManager; +import org.eclipse.milo.opcua.stack.core.types.UaRequestMessageType; +import org.eclipse.milo.opcua.stack.core.types.UaResponseMessageType; +import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; +import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime; +import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText; +import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; +import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger; +import org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType; +import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode; +import org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType; +import org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.CreateSessionRequest; +import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription; +import org.eclipse.milo.opcua.stack.core.types.structured.RequestHeader; +import org.eclipse.milo.opcua.stack.core.types.structured.UserTokenPolicy; +import org.eclipse.milo.opcua.stack.transport.client.ClientApplicationContext; +import org.eclipse.milo.opcua.stack.transport.server.OpcServerTransport; +import org.eclipse.milo.opcua.stack.transport.server.ServerApplicationContext; +import org.eclipse.milo.opcua.stack.transport.server.ServiceRequestContext; +import org.eclipse.milo.opcua.stack.transport.server.tcp.OpcTcpServerTransport; +import org.eclipse.milo.opcua.stack.transport.server.tcp.OpcTcpServerTransportConfig; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ubyte; +import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint; +import static org.junit.jupiter.api.Assertions.assertThrows; + + +class OpcTcpTransportTest extends SecurityFixture { + + static { + // Required for SecurityPolicy.Aes256_Sha256_RsaPss + Security.addProvider(new BouncyCastleProvider()); + } + + private static Stream provideSecurityParameters() { + return Stream.of( + Arguments.of(SecurityPolicy.None, MessageSecurityMode.None), + Arguments.of(SecurityPolicy.Basic256Sha256, MessageSecurityMode.Sign), + Arguments.of(SecurityPolicy.Basic256Sha256, MessageSecurityMode.SignAndEncrypt), + Arguments.of(SecurityPolicy.Aes128_Sha256_RsaOaep, MessageSecurityMode.Sign), + Arguments.of(SecurityPolicy.Aes128_Sha256_RsaOaep, MessageSecurityMode.SignAndEncrypt), + Arguments.of(SecurityPolicy.Aes256_Sha256_RsaPss, MessageSecurityMode.Sign), + Arguments.of(SecurityPolicy.Aes256_Sha256_RsaPss, MessageSecurityMode.SignAndEncrypt) + ); + } + + @ParameterizedTest + @MethodSource("provideSecurityParameters") + void connectThenDisconnect(SecurityPolicy securityPolicy, MessageSecurityMode messageSecurityMode) throws Exception { + OpcServerTransport serverTransport = bindServerTransport( + securityPolicy, + messageSecurityMode + ); + + var applicationContext = new ClientApplicationContext() { + @Override + public EndpointDescription getEndpoint() { + return newEndpointDescription(securityPolicy, messageSecurityMode); + } + + @Override + public Optional getKeyPair() { + return Optional.of(clientKeyPair); + } + + @Override + public Optional getCertificate() { + return Optional.of(clientCertificate); + } + + @Override + public Optional getCertificateChain() { + return Optional.of(new X509Certificate[]{clientCertificate}); + } + + @Override + public CertificateValidator getCertificateValidator() { + return new ClientCertificateValidator.InsecureValidator(); + } + + @Override + public EncodingContext getEncodingContext() { + return new DefaultEncodingContext(); + } + + @Override + public UInteger getRequestTimeout() { + return uint(5_000); + } + }; + + OpcTcpClientTransportConfig config = OpcTcpClientTransportConfig.newBuilder().build(); + + var transport = new OpcTcpClientTransport(config); + + System.out.println("connecting..."); + transport.connect(applicationContext).get(); + System.out.println("connected"); + + System.out.println("disconnecting..."); + transport.disconnect().get(); + System.out.println("disconnected"); + + System.out.println("unbinding server transport..."); + serverTransport.unbind(); + System.out.println("server transport unbound"); + } + + @Test + void openUnsecuredChannelAgainstSecuredEndpoint() throws Exception { + // Opening a SecureChannel with no security should be allowed even if all the configured + // endpoints require security. This is to give the receiving server application a chance + // to allow unsecured Discovery services to be implemented even when security is otherwise + // required. + + OpcServerTransport serverTransport = bindServerTransport( + SecurityPolicy.Basic256Sha256, + MessageSecurityMode.SignAndEncrypt + ); + + var applicationContext = new ClientApplicationContext() { + @Override + public EndpointDescription getEndpoint() { + return newEndpointDescription(SecurityPolicy.None, MessageSecurityMode.None); + } + + @Override + public Optional getKeyPair() { + return Optional.of(clientKeyPair); + } + + @Override + public Optional getCertificate() { + return Optional.of(clientCertificate); + } + + @Override + public Optional getCertificateChain() { + return Optional.of(new X509Certificate[]{clientCertificate}); + } + + @Override + public CertificateValidator getCertificateValidator() { + return new ClientCertificateValidator.InsecureValidator(); + } + + @Override + public EncodingContext getEncodingContext() { + return new DefaultEncodingContext(); + } + + @Override + public UInteger getRequestTimeout() { + return uint(5_000); + } + }; + + OpcTcpClientTransportConfig config = OpcTcpClientTransportConfig.newBuilder().build(); + + var transport = new OpcTcpClientTransport(config); + + System.out.println("connecting..."); + transport.connect(applicationContext).get(); + System.out.println("connected"); + + System.out.println("disconnecting..."); + transport.disconnect().get(); + System.out.println("disconnected"); + + System.out.println("unbinding server transport..."); + serverTransport.unbind(); + System.out.println("server transport unbound"); + } + + @Test + void securityPolicyRejectedOnUnsecuredChannel() throws Exception { + // We opened an unsecured channel even though only secured endpoints are available. + // Only Discovery services should be allowed. This is simulated by the test server + // transport. In reality, it's the server application responsible for this behavior. + OpcServerTransport serverTransport = bindServerTransport( + SecurityPolicy.Basic256Sha256, + MessageSecurityMode.SignAndEncrypt + ); + + var applicationContext = new ClientApplicationContext() { + @Override + public EndpointDescription getEndpoint() { + return newEndpointDescription(SecurityPolicy.None, MessageSecurityMode.None); + } + + @Override + public Optional getKeyPair() { + return Optional.of(clientKeyPair); + } + + @Override + public Optional getCertificate() { + return Optional.of(clientCertificate); + } + + @Override + public Optional getCertificateChain() { + return Optional.of(new X509Certificate[]{clientCertificate}); + } + + @Override + public CertificateValidator getCertificateValidator() { + return new ClientCertificateValidator.InsecureValidator(); + } + + @Override + public EncodingContext getEncodingContext() { + return new DefaultEncodingContext(); + } + + @Override + public UInteger getRequestTimeout() { + return uint(5_000); + } + }; + + OpcTcpClientTransportConfig config = OpcTcpClientTransportConfig.newBuilder().build(); + + var transport = new OpcTcpClientTransport(config); + + System.out.println("connecting..."); + transport.connect(applicationContext).get(); + System.out.println("connected"); + + assertThrows(ExecutionException.class, () -> createSession(transport)); + + serverTransport.unbind(); + } + + private static void createSession(OpcTcpClientTransport transport) throws Exception { + var header = new RequestHeader( + NodeId.NULL_VALUE, + DateTime.now(), + uint(0), + uint(0), + null, + uint(5_000), + null + ); + + var request = new CreateSessionRequest( + header, + ApplicationDescription.builder() + .applicationName(LocalizedText.NULL_VALUE) + .applicationUri("") + .applicationType(ApplicationType.Client) + .productUri("") + .applicationUri("") + .build(), + null, + "opc.tcp://localhost:12685", + "sessionName", + ByteString.NULL_VALUE, + ByteString.NULL_VALUE, + 60_000d, + UInteger.MAX + ); + + transport.sendRequestMessage(request).get(); + } + + private OpcServerTransport bindServerTransport( + SecurityPolicy securityPolicy, + MessageSecurityMode messageSecurityMode + ) throws Exception { + + var applicationContext = new ServerApplicationContext() { + + private final AtomicLong secureChannelId = new AtomicLong(0L); + private final AtomicLong secureChannelTokenId = new AtomicLong(0L); + + @Override + public List getEndpointDescriptions() { + return List.of(newEndpointDescription(securityPolicy, messageSecurityMode)); + } + + @Override + public EncodingContext getEncodingContext() { + return new DefaultEncodingContext(); + } + + @Override + public CertificateManager getCertificateManager() { + return serverCertificateManager; + } + + @Override + public CertificateValidator getCertificateValidator() { + return serverCertificateValidator; + } + + @Override + public Long getNextSecureChannelId() { + return secureChannelId.getAndIncrement(); + } + + @Override + public Long getNextSecureChannelTokenId() { + return secureChannelTokenId.getAndIncrement(); + } + + @Override + public CompletableFuture handleServiceRequest( + ServiceRequestContext context, + UaRequestMessageType requestMessage + ) { + + if (context.getSecureChannel().getSecurityPolicy() == SecurityPolicy.None) { + if (getEndpointDescriptions().stream() + .noneMatch(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))) { + + var errorMessage = new ErrorMessage( + StatusCodes.Bad_SecurityPolicyRejected, + StatusCodes.lookup(StatusCodes.Bad_SecurityPolicyRejected).map(ss -> ss[1]).orElse("") + ); + + context.getChannel().pipeline().fireUserEventTriggered(errorMessage); + + // won't complete, doesn't matter, we're closing down + return new CompletableFuture<>(); + } + } + + System.out.println("request: " + requestMessage); + + return CompletableFuture.failedFuture(new RuntimeException("not implemented")); + } + }; + + + OpcTcpServerTransportConfig config = OpcTcpServerTransportConfig.newBuilder().build(); + + var transport = new OpcTcpServerTransport(config); + transport.bind(applicationContext, new InetSocketAddress("localhost", 12685)); + return transport; + } + + private EndpointDescription newEndpointDescription( + SecurityPolicy securityPolicy, + MessageSecurityMode messageSecurityMode + ) { + + return new EndpointDescription( + "opc.tcp://localhost:12685", + new ApplicationDescription( + "uri:server", + "productUri", + LocalizedText.NULL_VALUE, + ApplicationType.Server, + null, null, + new String[]{"opc.tcp://localhost:12685"} + ), + ByteString.of(serverCertificateBytes), + messageSecurityMode, + securityPolicy.getUri(), + new UserTokenPolicy[]{ + new UserTokenPolicy( + "anonymous", + UserTokenType.Anonymous, + null, null, null + ) + }, + TransportProfile.TCP_UASC_UABINARY.getUri(), + ubyte(0) + ); + } + + private static class DefaultEncodingContext implements EncodingContext { + + private final NamespaceTable namespaceTable = new NamespaceTable(); + private final ServerTable serverTable = new ServerTable(); + + @Override + public DataTypeManager getDataTypeManager() { + return OpcUaDataTypeManager.getInstance(); + } + + @Override + public EncodingManager getEncodingManager() { + return OpcUaEncodingManager.getInstance(); + } + + @Override + public EncodingLimits getEncodingLimits() { + return EncodingLimits.DEFAULT; + } + + @Override + public NamespaceTable getNamespaceTable() { + return namespaceTable; + } + + @Override + public ServerTable getServerTable() { + return serverTable; + } + + } + +} diff --git a/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/SecurityFixture.java b/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/SecurityFixture.java new file mode 100644 index 000000000..763dee98b --- /dev/null +++ b/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/SecurityFixture.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.tcp; + +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; + +import org.eclipse.milo.opcua.stack.core.security.CertificateManager; +import org.eclipse.milo.opcua.stack.core.security.ServerCertificateValidator; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public abstract class SecurityFixture { + + private static final String CLIENT_ALIAS = "client-test-certificate"; + private static final String SERVER_ALIAS = "server-test-certificate"; + private static final String CLIENT_ALIAS_4096 = "client-4096"; + private static final String SERVER_ALIAS_4096 = "server-4096"; + private static final char[] PASSWORD = "test".toCharArray(); + + protected volatile X509Certificate clientCertificate; + protected volatile byte[] clientCertificateBytes; + protected volatile KeyPair clientKeyPair; + + protected volatile X509Certificate clientCertificate4096; + protected volatile byte[] clientCertificateBytes4096; + protected volatile KeyPair clientKeyPair4096; + + protected volatile X509Certificate serverCertificate; + protected volatile byte[] serverCertificateBytes; + protected volatile KeyPair serverKeyPair; + + protected volatile X509Certificate serverCertificate4096; + protected volatile byte[] serverCertificateBytes4096; + protected volatile KeyPair serverKeyPair4096; + + protected volatile CertificateManager serverCertificateManager; + protected volatile ServerCertificateValidator serverCertificateValidator; + + @BeforeAll + public void setUp() throws Exception { + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + + keyStore.load(getClass().getClassLoader().getResourceAsStream("test-keystore.pfx"), PASSWORD); + + { + Key clientPrivateKey = keyStore.getKey(CLIENT_ALIAS, PASSWORD); + if (clientPrivateKey instanceof PrivateKey) { + clientCertificate = (X509Certificate) keyStore.getCertificate(CLIENT_ALIAS); + clientCertificateBytes = clientCertificate.getEncoded(); + + PublicKey clientPublicKey = clientCertificate.getPublicKey(); + clientKeyPair = new KeyPair(clientPublicKey, (PrivateKey) clientPrivateKey); + } + } + + { + Key clientPrivateKey4096 = keyStore.getKey(CLIENT_ALIAS_4096, PASSWORD); + if (clientPrivateKey4096 instanceof PrivateKey) { + clientCertificate4096 = (X509Certificate) keyStore.getCertificate(CLIENT_ALIAS_4096); + clientCertificateBytes4096 = clientCertificate4096.getEncoded(); + + PublicKey clientPublicKey = clientCertificate4096.getPublicKey(); + clientKeyPair4096 = new KeyPair(clientPublicKey, (PrivateKey) clientPrivateKey4096); + } + } + + { + Key serverPrivateKey = keyStore.getKey(SERVER_ALIAS, PASSWORD); + if (serverPrivateKey instanceof PrivateKey) { + serverCertificate = (X509Certificate) keyStore.getCertificate(SERVER_ALIAS); + serverCertificateBytes = serverCertificate.getEncoded(); + + PublicKey serverPublicKey = serverCertificate.getPublicKey(); + serverKeyPair = new KeyPair(serverPublicKey, (PrivateKey) serverPrivateKey); + } + } + + { + Key serverPrivateKey4096 = keyStore.getKey(SERVER_ALIAS_4096, PASSWORD); + if (serverPrivateKey4096 instanceof PrivateKey) { + serverCertificate4096 = (X509Certificate) keyStore.getCertificate(SERVER_ALIAS_4096); + serverCertificateBytes4096 = serverCertificate4096.getEncoded(); + + PublicKey serverPublicKey = serverCertificate4096.getPublicKey(); + serverKeyPair4096 = new KeyPair(serverPublicKey, (PrivateKey) serverPrivateKey4096); + } + } + + serverCertificateManager = new TestCertificateManager( + serverKeyPair, + serverCertificate + ); + + serverCertificateValidator = new TestServerCertificateValidator(clientCertificate); + } + +} diff --git a/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/TestCertificateManager.java b/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/TestCertificateManager.java new file mode 100644 index 000000000..a81941634 --- /dev/null +++ b/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/TestCertificateManager.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.tcp; + +import java.security.KeyPair; +import java.security.cert.X509Certificate; +import java.util.Optional; +import java.util.Set; + +import org.eclipse.milo.opcua.stack.core.security.CertificateManager; +import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString; + +public class TestCertificateManager implements CertificateManager { + + private final KeyPair keyPair; + private final X509Certificate certificate; + + public TestCertificateManager(KeyPair keyPair, X509Certificate certificate) { + this.keyPair = keyPair; + this.certificate = certificate; + } + + @Override + public Optional getKeyPair(ByteString thumbprint) { + return Optional.of(keyPair); + } + + @Override + public Optional getCertificate(ByteString thumbprint) { + return Optional.of(certificate); + } + + @Override + public Optional getCertificateChain(ByteString thumbprint) { + return getCertificate(thumbprint).map(c -> new X509Certificate[]{c}); + } + + @Override + public Set getKeyPairs() { + return Set.of(keyPair); + } + + @Override + public Set getCertificates() { + return Set.of(certificate); + } + +} diff --git a/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/TestServerCertificateValidator.java b/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/TestServerCertificateValidator.java new file mode 100644 index 000000000..30ff7be75 --- /dev/null +++ b/opc-ua-stack/transport/src/test/java/org/eclipse/milo/opcua/stack/transport/client/tcp/TestServerCertificateValidator.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 the Eclipse Milo Authors + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.milo.opcua.stack.transport.client.tcp; + +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.milo.opcua.stack.core.security.ServerCertificateValidator; + +public class TestServerCertificateValidator implements ServerCertificateValidator { + + private final Set trustedCertificates = ConcurrentHashMap.newKeySet(); + + public TestServerCertificateValidator(X509Certificate certificate) { + trustedCertificates.add(certificate); + } + + public TestServerCertificateValidator(X509Certificate... certificates) { + Collections.addAll(trustedCertificates, certificates); + } + + @Override + public void validateCertificateChain(List certificateChain) { + // noop + } + + @Override + public void validateCertificateChain(List certificateChain, String applicationUri) { + // noop + } + +} diff --git a/opc-ua-stack/transport/src/test/resources/simplelogger.properties b/opc-ua-stack/transport/src/test/resources/simplelogger.properties new file mode 100644 index 000000000..720a2fda8 --- /dev/null +++ b/opc-ua-stack/transport/src/test/resources/simplelogger.properties @@ -0,0 +1,11 @@ +# +# Copyright (c) 2022 the Eclipse Milo Authors +# +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# + +org.slf4j.simpleLogger.defaultLogLevel=info diff --git a/opc-ua-stack/transport/src/test/resources/test-keystore.pfx b/opc-ua-stack/transport/src/test/resources/test-keystore.pfx new file mode 100644 index 000000000..f137d6e7b Binary files /dev/null and b/opc-ua-stack/transport/src/test/resources/test-keystore.pfx differ