All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.milo.opcua.sdk.client.OpcUaClient Maven / Gradle / Ivy

There is a newer version: 0.6.14
Show newest version
/*
 * 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.client;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.function.Predicate;

import org.eclipse.milo.opcua.sdk.client.api.ServiceFaultListener;
import org.eclipse.milo.opcua.sdk.client.api.UaClient;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfigBuilder;
import org.eclipse.milo.opcua.sdk.client.model.ObjectTypeInitializer;
import org.eclipse.milo.opcua.sdk.client.model.VariableTypeInitializer;
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.Identifiers;
import org.eclipse.milo.opcua.stack.core.NamespaceTable;
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.UaServiceFaultException;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.serialization.SerializationContext;
import org.eclipse.milo.opcua.stack.core.serialization.UaRequestMessage;
import org.eclipse.milo.opcua.stack.core.serialization.UaResponseMessage;
import org.eclipse.milo.opcua.stack.core.types.DataTypeManager;
import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString;
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;
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.MonitoringMode;
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.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.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.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.BrowseRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResponse;
import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodRequest;
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.CreateMonitoredItemsRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.CreateMonitoredItemsResponse;
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.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.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.EndpointDescription;
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.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.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.MonitoredItemModifyRequest;
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.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.RegisterNodesRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.RegisterNodesResponse;
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.ServiceFault;
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.SubscriptionAcknowledgement;
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.UnregisterNodesRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.UnregisterNodesResponse;
import org.eclipse.milo.opcua.stack.core.types.structured.ViewDescription;
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.util.ExecutionQueue;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.collect.Lists.newCopyOnWriteArrayList;
import static org.eclipse.milo.opcua.sdk.client.session.SessionFsm.SessionInitializer;
import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ushort;
import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.a;

public class OpcUaClient implements UaClient {

    public static final String SDK_VERSION =
        ManifestUtil.read("X-SDK-Version").orElse("dev");

    static {
        Logger logger = LoggerFactory.getLogger(OpcUaClient.class);
        logger.info("Eclipse Milo OPC UA Stack version: {}", Stack.VERSION);
        logger.info("Eclipse Milo OPC UA Client SDK version: {}", SDK_VERSION);
    }

    /**
     * Create an {@link OpcUaClient} configured with {@code config}.
     *
     * @param config the {@link OpcUaClientConfig}.
     * @return an {@link OpcUaClient} configured with {@code config}.
     * @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);

        return new OpcUaClient(config, stackClient);
    }

    /**
     * Select the first endpoint with no security that allows anonymous connections and create an
     * {@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 * 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. * @return an {@link OpcUaClient} configured to connect to the server identified by * {@code endpointUrl}. * @throws UaException if the endpoints could not be retrieved or the client could not be * created. */ public static OpcUaClient create(String endpointUrl) throws UaException { // select the first EndpointDescription with no security and anonymous authentication Predicate predicate = e -> SecurityPolicy.None.getUri().equals(e.getSecurityPolicyUri()) && Arrays.stream(e.getUserIdentityTokens()) .anyMatch(p -> p.getTokenType() == UserTokenType.Anonymous); return create( endpointUrl, endpoints -> endpoints.stream() .filter(predicate) .findFirst(), OpcUaClientConfigBuilder::build ); } /** * 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}. * @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 ) throws UaException { try { List endpoints = DiscoveryClient.getEndpoints(endpointUrl).get(); EndpointDescription endpoint = selectEndpoint.apply(endpoints).orElseThrow(() -> new UaException( StatusCodes.Bad_ConfigurationError, "no endpoint selected" ) ); OpcUaClientConfigBuilder builder = OpcUaClientConfig.builder() .setEndpoint(endpoint); return create(buildConfig.apply(builder)); } catch (InterruptedException | ExecutionException e) { if (!endpointUrl.endsWith("/discovery")) { StringBuilder discoveryUrl = new StringBuilder(endpointUrl); if (!endpointUrl.endsWith("/")) { discoveryUrl.append("/"); } discoveryUrl.append("discovery"); return create(discoveryUrl.toString(), selectEndpoint, buildConfig); } else { throw UaException.extract(e) .orElseGet(() -> new UaException(e)); } } } private final Logger logger = LoggerFactory.getLogger(getClass()); private final List faultListeners = newCopyOnWriteArrayList(); private final ExecutionQueue faultNotificationQueue; private final AddressSpace addressSpace; private final ObjectTypeManager objectTypeManager = new ObjectTypeManager(); private final VariableTypeManager variableTypeManager = new VariableTypeManager(); private final OpcUaSubscriptionManager subscriptionManager; private final SessionFsm sessionFsm; private final OpcUaClientConfig config; private final UaStackClient stackClient; public OpcUaClient(OpcUaClientConfig config, UaStackClient stackClient) { this.config = config; this.stackClient = stackClient; sessionFsm = SessionFsmFactory.newSessionFsm(this); sessionFsm.addInitializer((client, session) -> { logger.debug("SessionInitializer: NamespaceTable"); RequestHeader requestHeader = newRequestHeader(session.getAuthenticationToken()); ReadRequest readRequest = new ReadRequest( requestHeader, 0.0, TimestampsToReturn.Neither, new ReadValueId[]{ new ReadValueId( Identifiers.Server_NamespaceArray, AttributeId.Value.uid(), null, QualifiedName.NULL_VALUE) } ); return client.sendRequest(readRequest) .thenApply(ReadResponse.class::cast) .thenApply(response -> Objects.requireNonNull(response.getResults())) .thenApply(results -> (String[]) results[0].getValue().getValue()) .thenAccept(this::updateNamespaceTable) .thenApply(v -> Unit.VALUE) .exceptionally(ex -> { logger.warn("SessionInitializer: NamespaceTable", ex); return Unit.VALUE; }); }); faultNotificationQueue = new ExecutionQueue(config.getExecutor()); addressSpace = new AddressSpace(this); subscriptionManager = new OpcUaSubscriptionManager(this); ObjectTypeInitializer.initialize( stackClient.getNamespaceTable(), objectTypeManager ); VariableTypeInitializer.initialize( stackClient.getNamespaceTable(), variableTypeManager ); } @Override public OpcUaClientConfig getConfig() { return config; } public UaStackClient getStackClient() { return stackClient; } @Override public AddressSpace getAddressSpace() { return addressSpace; } public DataTypeManager getDataTypeManager() { return stackClient.getDataTypeManager(); } public ObjectTypeManager getObjectTypeManager() { return objectTypeManager; } public VariableTypeManager getVariableTypeManager() { return variableTypeManager; } /** * Get the local copy of the server's NamespaceTable. * * @return the current local value for server's NamespaceTable. */ public NamespaceTable getNamespaceTable() { return stackClient.getNamespaceTable(); } /** * Read the server's NamespaceTable and update the local copy. * * @return the updated {@link NamespaceTable}. * @throws UaException if an operation- or service-level error occurs. */ public NamespaceTable readNamespaceTable() throws UaException { try { return readNamespaceTableAsync().get(); } catch (InterruptedException | ExecutionException e) { throw UaException.extract(e) .orElse(new UaException(StatusCodes.Bad_UnexpectedError, e)); } } /** * Read the server's NamespaceTable and update the local copy. *

* This call completes asynchronously. * * @return a {@link CompletableFuture} that completes successfully with the updated * {@link NamespaceTable} or completes exceptionally if a service- or operation-level error * occurs. */ public CompletableFuture readNamespaceTableAsync() { return getSession().thenCompose(session -> { RequestHeader requestHeader = newRequestHeader(session.getAuthenticationToken()); ReadRequest readRequest = new ReadRequest( requestHeader, 0.0, TimestampsToReturn.Neither, new ReadValueId[]{ new ReadValueId( Identifiers.Server_NamespaceArray, AttributeId.Value.uid(), null, QualifiedName.NULL_VALUE) } ); CompletableFuture namespaceArray = sendRequest(readRequest) .thenApply(ReadResponse.class::cast) .thenApply(response -> Objects.requireNonNull(response.getResults())) .thenApply(results -> (String[]) results[0].getValue().getValue()); return namespaceArray .thenAccept(this::updateNamespaceTable) .thenApply(v -> getNamespaceTable()); }); } private void updateNamespaceTable(String[] namespaceArray) { getNamespaceTable().update(uriTable -> { uriTable.clear(); uriTable.put(ushort(0), Namespaces.OPC_UA); if (namespaceArray.length > UShort.MAX_VALUE) { logger.warn("NamespaceTable returned by " + "server contains " + namespaceArray.length + " entries"); } for (int i = 1; i < namespaceArray.length && i < UShort.MAX_VALUE; i++) { String uri = namespaceArray[i]; if (uri != null && !uriTable.containsValue(uri)) { uriTable.put(ushort(i), uri); } } }); } public SerializationContext getSerializationContext() { return stackClient.getSerializationContext(); } /** * Build a new {@link RequestHeader} using a null authentication token. * * @return a new {@link RequestHeader} with a null authentication token. */ public RequestHeader newRequestHeader() { return newRequestHeader(NodeId.NULL_VALUE, config.getRequestTimeout()); } /** * Build a new {@link RequestHeader} using {@code authToken}. * * @param authToken the authentication token (from the session) to use. * @return a new {@link RequestHeader}. */ 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}. * * @param authToken the authentication token (from the session) to use. * @param requestTimeout the custom request timeout to use. * @return a new {@link RequestHeader}. */ public RequestHeader newRequestHeader(NodeId authToken, UInteger requestTimeout) { return getStackClient().newRequestHeader(authToken, requestTimeout); } @Override public CompletableFuture connect() { return getStackClient() .connect() .thenCompose(c -> sessionFsm.openSession()) .thenApply(s -> OpcUaClient.this); } @Override public CompletableFuture disconnect() { return sessionFsm .closeSession() .exceptionally(ex -> Unit.VALUE) .thenCompose(u -> getStackClient() .disconnect() .thenApply(c -> OpcUaClient.this)) .exceptionally(ex -> OpcUaClient.this); } @Override public OpcUaSubscriptionManager getSubscriptionManager() { return subscriptionManager; } @Override public CompletableFuture read(double maxAge, TimestampsToReturn timestampsToReturn, List readValueIds) { return getSession().thenCompose(session -> { ReadRequest request = new ReadRequest( newRequestHeader(session.getAuthenticationToken()), maxAge, timestampsToReturn, a(readValueIds, ReadValueId.class) ); return sendRequest(request); }); } @Override public CompletableFuture write(List writeValues) { return getSession().thenCompose(session -> { WriteRequest request = new WriteRequest( newRequestHeader(session.getAuthenticationToken()), a(writeValues, WriteValue.class) ); return sendRequest(request); }); } @Override public CompletableFuture historyRead(HistoryReadDetails historyReadDetails, TimestampsToReturn timestampsToReturn, boolean releaseContinuationPoints, List nodesToRead) { return getSession().thenCompose(session -> { HistoryReadRequest request = new HistoryReadRequest( newRequestHeader(session.getAuthenticationToken()), ExtensionObject.encode(getSerializationContext(), historyReadDetails), timestampsToReturn, releaseContinuationPoints, a(nodesToRead, HistoryReadValueId.class) ); return sendRequest(request); }); } @Override public CompletableFuture historyUpdate(List historyUpdateDetails) { return getSession().thenCompose(session -> { ExtensionObject[] details = historyUpdateDetails.stream() .map(hud -> ExtensionObject.encode(getSerializationContext(), hud)) .toArray(ExtensionObject[]::new); HistoryUpdateRequest request = new HistoryUpdateRequest( newRequestHeader(session.getAuthenticationToken()), details ); return sendRequest(request); }); } @Override public CompletableFuture browse(ViewDescription viewDescription, UInteger maxReferencesPerNode, List nodesToBrowse) { return getSession().thenCompose(session -> { BrowseRequest request = new BrowseRequest( newRequestHeader(session.getAuthenticationToken()), viewDescription, maxReferencesPerNode, a(nodesToBrowse, BrowseDescription.class) ); return sendRequest(request); }); } @Override public CompletableFuture browseNext(boolean releaseContinuationPoints, List continuationPoints) { return getSession().thenCompose(session -> { BrowseNextRequest request = new BrowseNextRequest( newRequestHeader(session.getAuthenticationToken()), releaseContinuationPoints, a(continuationPoints, ByteString.class) ); return sendRequest(request); }); } @Override public CompletableFuture translateBrowsePaths(List browsePaths) { return getSession().thenCompose(session -> { TranslateBrowsePathsToNodeIdsRequest request = new TranslateBrowsePathsToNodeIdsRequest( newRequestHeader(session.getAuthenticationToken()), a(browsePaths, BrowsePath.class) ); return sendRequest(request); }); } @Override public CompletableFuture registerNodes(List nodesToRegister) { return getSession().thenCompose(session -> { RegisterNodesRequest request = new RegisterNodesRequest( newRequestHeader(session.getAuthenticationToken()), a(nodesToRegister, NodeId.class) ); return sendRequest(request); }); } @Override public CompletableFuture unregisterNodes(List nodesToUnregister) { return getSession().thenCompose(session -> { UnregisterNodesRequest request = new UnregisterNodesRequest( newRequestHeader(session.getAuthenticationToken()), a(nodesToUnregister, NodeId.class) ); return sendRequest(request); }); } @Override public CompletableFuture call(List methodsToCall) { return getSession().thenCompose(session -> { CallRequest request = new CallRequest( newRequestHeader(session.getAuthenticationToken()), a(methodsToCall, CallMethodRequest.class) ); return sendRequest(request); }); } @Override public CompletableFuture createSubscription( double requestedPublishingInterval, UInteger requestedLifetimeCount, UInteger requestedMaxKeepAliveCount, UInteger maxNotificationsPerPublish, boolean publishingEnabled, UByte priority) { return getSession().thenCompose(session -> { CreateSubscriptionRequest request = new CreateSubscriptionRequest( newRequestHeader(session.getAuthenticationToken()), requestedPublishingInterval, requestedLifetimeCount, requestedMaxKeepAliveCount, maxNotificationsPerPublish, publishingEnabled, priority ); return sendRequest(request); }); } @Override public CompletableFuture modifySubscription( UInteger subscriptionId, double requestedPublishingInterval, UInteger requestedLifetimeCount, UInteger requestedMaxKeepAliveCount, UInteger maxNotificationsPerPublish, UByte priority) { return getSession().thenCompose(session -> { ModifySubscriptionRequest request = new ModifySubscriptionRequest( newRequestHeader(session.getAuthenticationToken()), subscriptionId, requestedPublishingInterval, requestedLifetimeCount, requestedMaxKeepAliveCount, maxNotificationsPerPublish, priority ); return sendRequest(request); }); } @Override public CompletableFuture deleteSubscriptions(List subscriptionIds) { return getSession().thenCompose(session -> { DeleteSubscriptionsRequest request = new DeleteSubscriptionsRequest( newRequestHeader(session.getAuthenticationToken()), a(subscriptionIds, UInteger.class) ); return sendRequest(request); }); } @Override public CompletableFuture transferSubscriptions(List subscriptionIds, boolean sendInitialValues) { return getSession().thenCompose(session -> { TransferSubscriptionsRequest request = new TransferSubscriptionsRequest( newRequestHeader(session.getAuthenticationToken()), a(subscriptionIds, UInteger.class), sendInitialValues ); return sendRequest(request); }); } @Override public CompletableFuture setPublishingMode(boolean publishingEnabled, List subscriptionIds) { return getSession().thenCompose(session -> { SetPublishingModeRequest request = new SetPublishingModeRequest( newRequestHeader(session.getAuthenticationToken()), publishingEnabled, a(subscriptionIds, UInteger.class) ); return sendRequest(request); }); } @Override public CompletableFuture publish(List subscriptionAcknowledgements) { return getSession().thenCompose(session -> { PublishRequest request = new PublishRequest( newRequestHeader(session.getAuthenticationToken()), a(subscriptionAcknowledgements, SubscriptionAcknowledgement.class) ); return sendRequest(request); }); } @Override public CompletableFuture republish(UInteger subscriptionId, UInteger retransmitSequenceNumber) { return getSession().thenCompose(session -> { RepublishRequest request = new RepublishRequest( newRequestHeader(session.getAuthenticationToken()), subscriptionId, retransmitSequenceNumber ); return sendRequest(request); }); } @Override public CompletableFuture createMonitoredItems( UInteger subscriptionId, TimestampsToReturn timestampsToReturn, List itemsToCreate) { return getSession().thenCompose(session -> { CreateMonitoredItemsRequest request = new CreateMonitoredItemsRequest( newRequestHeader(session.getAuthenticationToken()), subscriptionId, timestampsToReturn, a(itemsToCreate, MonitoredItemCreateRequest.class) ); return sendRequest(request); }); } @Override public CompletableFuture modifyMonitoredItems( UInteger subscriptionId, TimestampsToReturn timestampsToReturn, List itemsToModify) { return getSession().thenCompose(session -> { ModifyMonitoredItemsRequest request = new ModifyMonitoredItemsRequest( newRequestHeader(session.getAuthenticationToken()), subscriptionId, timestampsToReturn, a(itemsToModify, MonitoredItemModifyRequest.class) ); return sendRequest(request); }); } @Override public CompletableFuture deleteMonitoredItems(UInteger subscriptionId, List monitoredItemIds) { return getSession().thenCompose(session -> { DeleteMonitoredItemsRequest request = new DeleteMonitoredItemsRequest( newRequestHeader(session.getAuthenticationToken()), subscriptionId, a(monitoredItemIds, UInteger.class) ); return sendRequest(request); }); } @Override public CompletableFuture setMonitoringMode(UInteger subscriptionId, MonitoringMode monitoringMode, List monitoredItemIds) { return getSession().thenCompose(session -> { SetMonitoringModeRequest request = new SetMonitoringModeRequest( newRequestHeader(session.getAuthenticationToken()), subscriptionId, monitoringMode, a(monitoredItemIds, UInteger.class) ); return sendRequest(request); }); } @Override public CompletableFuture setTriggering(UInteger subscriptionId, UInteger triggeringItemId, List linksToAdd, List linksToRemove) { return getSession().thenCompose(session -> { SetTriggeringRequest request = new SetTriggeringRequest( newRequestHeader(session.getAuthenticationToken()), subscriptionId, triggeringItemId, a(linksToAdd, UInteger.class), a(linksToRemove, UInteger.class) ); return sendRequest(request); }); } @Override public CompletableFuture addNodes(List nodesToAdd) { return getSession().thenCompose(session -> { AddNodesRequest request = new AddNodesRequest( newRequestHeader(session.getAuthenticationToken()), a(nodesToAdd, AddNodesItem.class) ); return sendRequest(request); }); } @Override public CompletableFuture addReferences(List referencesToAdd) { return getSession().thenCompose(session -> { AddReferencesRequest request = new AddReferencesRequest( newRequestHeader(session.getAuthenticationToken()), a(referencesToAdd, AddReferencesItem.class) ); return sendRequest(request); }); } @Override public CompletableFuture deleteNodes(List nodesToDelete) { return getSession().thenCompose(session -> { DeleteNodesRequest request = new DeleteNodesRequest( newRequestHeader(session.getAuthenticationToken()), a(nodesToDelete, DeleteNodesItem.class) ); return sendRequest(request); }); } @Override public CompletableFuture deleteReferences(List referencesToDelete) { return getSession().thenCompose(session -> { DeleteReferencesRequest request = new DeleteReferencesRequest( newRequestHeader(session.getAuthenticationToken()), a(referencesToDelete, DeleteReferencesItem.class) ); return sendRequest(request); }); } @Override public CompletableFuture getSession() { return sessionFsm.getSession(); } @Override public CompletableFuture sendRequest(UaRequestMessage request) { CompletableFuture f = getStackClient().sendRequest(request); if (faultListeners.size() > 0) { f.whenComplete(this::maybeHandleServiceFault); } return f.thenApply(r -> (T) r); } private void maybeHandleServiceFault(UaResponseMessage response, Throwable ex) { if (faultListeners.isEmpty()) return; if (ex != null) { if (ex instanceof UaServiceFaultException) { UaServiceFaultException faultException = (UaServiceFaultException) ex; ServiceFault serviceFault = faultException.getServiceFault(); logger.debug("Notifying {} ServiceFaultListeners", faultListeners.size()); faultNotificationQueue.submit(() -> faultListeners.forEach(h -> h.onServiceFault(serviceFault))); } else if (ex.getCause() instanceof UaServiceFaultException) { UaServiceFaultException faultException = (UaServiceFaultException) ex.getCause(); ServiceFault serviceFault = faultException.getServiceFault(); logger.debug("Notifying {} ServiceFaultListeners", faultListeners.size()); faultNotificationQueue.submit(() -> faultListeners.forEach(h -> h.onServiceFault(serviceFault))); } } } public void addFaultListener(ServiceFaultListener faultListener) { faultListeners.add(faultListener); logger.debug("Added ServiceFaultListener: {}", faultListener); } public void removeFaultListener(ServiceFaultListener faultListener) { faultListeners.remove(faultListener); logger.debug("Removed ServiceFaultListener: {}", faultListener); } public void addSessionActivityListener(SessionActivityListener listener) { sessionFsm.addActivityListener(listener); logger.debug("Added SessionActivityListener: {}", listener); } public void removeSessionActivityListener(SessionActivityListener listener) { sessionFsm.removeActivityListener(listener); logger.debug("Removed SessionActivityListener: {}", listener); } public void addSessionInitializer(SessionInitializer initializer) { sessionFsm.addInitializer(initializer); logger.debug("Added SessionInitializer: {}", initializer); } public void removeSessionInitializer(SessionInitializer initializer) { sessionFsm.removeInitializer(initializer); logger.debug("Removed SessionInitializer: {}", initializer); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy