code: /*
   * 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.sdk.client.api.subscriptions;
  
  import java.util.List;
  import java.util.concurrent.CompletableFuture;
  import java.util.stream.Collectors;
  
  import com.google.common.collect.ImmutableList;
  import org.eclipse.milo.opcua.sdk.client.api.UaSession;
  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.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.MonitoringMode;
  import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
  import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest;
  import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemModifyRequest;
  
  public interface UaSubscription {
  
      /**
       * @return the server-assigned id for this {@link UaSubscription}.
       */
      UInteger getSubscriptionId();
  
      /**
       * @return the last requested publishing interval of this {@link UaSubscription}.
       */
      double getRequestedPublishingInterval();
  
      /**
       * @return the actual/revised publishing interval of this {@link UaSubscription}.
       */
      double getRevisedPublishingInterval();
  
      /**
       * @return the last requested lifetime count of this {@link UaSubscription}.
       */
      UInteger getRequestedLifetimeCount();
  
      /**
       * @return the actual/revised lifetime count of this {@link UaSubscription}.
       */
      UInteger getRevisedLifetimeCount();
  
      /**
       * @return the last requested max keep-alive count of this {@link UaSubscription}.
       */
      UInteger getRequestedMaxKeepAliveCount();
  
      /**
       * @return the actual/revised max keep-alive count of this {@link UaSubscription}.
       */
      UInteger getRevisedMaxKeepAliveCount();
  
      /**
       * @return the maximum number of notifications that will be returned in any publish response.
       */
      UInteger getMaxNotificationsPerPublish();
  
      /**
       * @return {@code true} if publishing is enabled.
       */
      boolean isPublishingEnabled();
  
      /**
       * @return the relative priority assigned to this {@link UaSubscription}.
       */
      UByte getPriority();
  
      /**
       * @return an {@link ImmutableList} of this {@link UaSubscription}'s {@link UaMonitoredItem}s.
       */
      ImmutableList<UaMonitoredItem> getMonitoredItems();
  
      /**
       * @return the next available client handle, unique within the context of this {@link UaSubscription}.
       */
      UInteger nextClientHandle();
  
      /**
       * Create one or more {@link UaMonitoredItem}s.
       * <p>
       * Callers must check the quality of each of the returned {@link UaMonitoredItem}s; it is not to be assumed that
       * all items were created successfully. Any item with a bad quality will not be updated nor will it be part of the
       * subscription's bookkeeping.
       * <p>
       * <b>WARNING:</b> items must be created in {@link MonitoringMode#Sampling} and then later set to
       * {@link MonitoringMode#Reporting} <i>after</i> consumers have been set in order to avoid a race condition where
       * the initial values arrive before the consumers are set. Alternatively, you can use
       * {@link #createMonitoredItems(TimestampsToReturn, List, ItemCreationCallback)} to avoid this race condition.
       *
       * @param timestampsToReturn the {@link TimestampsToReturn}.
       * @param itemsToCreate      a list of {@link MonitoredItemCreateRequest}s.
       * @return a list of {@link UaMonitoredItem}s.
       */
      CompletableFuture<List<UaMonitoredItem>> createMonitoredItems(TimestampsToReturn timestampsToReturn,
                                                                    List<MonitoredItemCreateRequest> itemsToCreate);
  
      /**
       * Create one or more {@link UaMonitoredItem}s.
       * <p>
       * Callers must check the quality of each of the returned {@link UaMonitoredItem}s; it is not to be assumed that
       * all items were created successfully. Any item with a bad quality will not be updated nor will it be part of the
       * subscription's bookkeeping.
       * <p>
       * {@code itemCreationCallback} will be invoked for each successfully created {@link UaMonitoredItem}. Callers
       * should use this opportunity to register any value or event consumers on the item, as this is the only time in
       * which it is guaranteed no values or events will be delivered to the item yet.
       *
       * @param timestampsToReturn   the {@link TimestampsToReturn}.
       * @param itemsToCreate        a list of {@link MonitoredItemCreateRequest}s.
       * @param itemCreationCallback callback to be invoked for each successfully created {@link UaMonitoredItem}.
       * @return a list of {@link UaMonitoredItem}s.
       */
      CompletableFuture<List<UaMonitoredItem>> createMonitoredItems(
          TimestampsToReturn timestampsToReturn,
          List<MonitoredItemCreateRequest> itemsToCreate,
          ItemCreationCallback itemCreationCallback);
  
      /**
       * Modify one or more {@link UaMonitoredItem}s.
       *
       * @param timestampsToReturn the {@link TimestampsToReturn} to set for each item.
       * @param itemsToModify      a list of {@link MonitoredItemModifyRequest}s.
       * @return a {@link CompletableFuture} containing a list of {@link StatusCode}s, the size and order matching that
       * of {@code itemsToModify}.
       */
      CompletableFuture<List<StatusCode>> modifyMonitoredItems(TimestampsToReturn timestampsToReturn,
                                                               List<MonitoredItemModifyRequest> itemsToModify);
  
      /**
       * Delete on or more {@link UaMonitoredItem}s.
       *
       * @param itemsToDelete the items to delete.
       * @return a {@link CompletableFuture} containing a list of {@link StatusCode}s, the size and order matching that
       * of {@code itemsToDelete}.
       */
      CompletableFuture<List<StatusCode>> deleteMonitoredItems(List<UaMonitoredItem> itemsToDelete);
  
      /**
       * Set the {@link MonitoringMode} for one or more {@link UaMonitoredItem}s.
       *
       * @param monitoringMode the {@link MonitoringMode} to set.
       * @param items          the {@link UaMonitoredItem}s to set the mode on.
       * @return a {@link CompletableFuture} containing a list of {@link StatusCode}s, the size and order matching that
       * of {@code items}.
       */
      CompletableFuture<List<StatusCode>> setMonitoringMode(MonitoringMode monitoringMode, List<UaMonitoredItem> items);
  
      /**
       * Set the publishing mode for this subscription.
       *
       * @param publishingEnabled {@code true} if publishing should be enabled.
       * @return a {@link CompletableFuture} containing a {@link StatusCode} representing the result of this operation.
       */
      CompletableFuture<StatusCode> setPublishingMode(boolean publishingEnabled);
  
      /**
       * Add triggering links between the item identified by {@code triggerItemId} and the items identified by
       * {@code linksToAdd}.
       *
       * @param triggeringItemId the id of the triggering item.
       * @param linksToAdd       the ids of the triggered items.
       * @return a list of {@link StatusCode}s corresponding to the items in {@code linksToAdd}.
       */
      CompletableFuture<List<StatusCode>> addTriggeringLinks(UInteger triggeringItemId, List<UInteger> linksToAdd);
  
      /**
       * Add triggering links between the {@code triggeringItem} and the items in {@code linksToAdd}.
       *
       * @param triggeringItem the triggering item.
       * @param linksToAdd     the triggered items.
       * @return a list of {@link StatusCode}s corresponding to the items in {@code linksToAdd}.
       */
      default CompletableFuture<List<StatusCode>> addTriggeringLinks(
          UaMonitoredItem triggeringItem,
          List<UaMonitoredItem> linksToAdd
      ) {
  
          return addTriggeringLinks(
              triggeringItem.getMonitoredItemId(),
              linksToAdd.stream()
                  .map(UaMonitoredItem::getMonitoredItemId)
                  .collect(Collectors.toList())
          );
      }
  
      /**
       * Remove triggering links between the item identified by {@code triggeringItemId} and the items identified by
       * {@code linksToRemove}.
       *
       * @param triggeringItemId the id of the triggering item.
       * @param linksToRemove    the ids of the triggered items.
       * @return a list of {@link StatusCode}s corresponding to the items in {@code linksToRemove}.
       */
      CompletableFuture<List<StatusCode>> removeTriggeringLinks(UInteger triggeringItemId, List<UInteger> linksToRemove);
  
      /**
       * Remove triggering links between {@code triggeringItem} and the items in {@code linksToRemove}.
       *
       * @param triggeringItem the triggering item.
       * @param linksToRemove  the triggered items.
       * @return a list of {@link StatusCode}s corresponding to the items in {@code linksToRemove}.
       */
      default CompletableFuture<List<StatusCode>> removeTriggeringLinks(
          UaMonitoredItem triggeringItem,
          List<UaMonitoredItem> linksToRemove
      ) {
  
          return removeTriggeringLinks(
              triggeringItem.getMonitoredItemId(),
              linksToRemove.stream()
                  .map(UaMonitoredItem::getMonitoredItemId)
                  .collect(Collectors.toList())
          );
      }
  
      /**
       * Add a {@link NotificationListener}.
       *
       * @param listener the {@link NotificationListener} to add.
       */
      void addNotificationListener(NotificationListener listener);
  
      /**
       * Remove a {@link NotificationListener}.
       *
       * @param listener the {@link NotificationListener} to remove.
       */
      void removeNotificationListener(NotificationListener listener);
  
      interface ItemCreationCallback {
  
          void onItemCreated(UaMonitoredItem item, int index);
  
      }
  
  
      interface NotificationListener {
  
          /**
           * A notification containing data value changes for this {@link UaSubscription} has arrived.
           * <p>
           * This callback is invoked after all individual item callbacks and is offered as an alternative to defining
           * callbacks on a per-item basis. Its use is not required.
           *
           * @param subscription   the {@link UaSubscription} that received the notification.
           * @param monitoredItems the {@link UaMonitoredItem}s that received a data value change.
           * @param dataValues     the corresponding {@link DataValue} change for each item in {@code monitoredItems}.
           * @param publishTime    the time on the server at which this notification was published.
           */
          default void onDataChangeNotification(UaSubscription subscription,
                                                List<UaMonitoredItem> monitoredItems,
                                                List<DataValue> dataValues,
                                                DateTime publishTime) {}
  
          /**
           * A notification containing events for this {@link UaSubscription} has arrived.
           * <p>
           * This callback is invoked after all individual item callbacks and is offered as an alternative to defining
           * callbacks on a per-item basis. Its use is not required.
           *
           * @param subscription   the {@link UaSubscription} that received the notification.
           * @param monitoredItems the {@link UaMonitoredItem}s that received an event notification.
           * @param eventFields    the corresponding event field values for each item in {@code monitoredItems}.
           * @param publishTime    the time on the server at which this notification was published.
           */
          default void onEventNotification(UaSubscription subscription,
                                           List<UaMonitoredItem> monitoredItems,
                                           List<Variant[]> eventFields,
                                           DateTime publishTime) {}
  
          /**
           * A keep-alive message was received.
           *
           * @param subscription the {@link UaSubscription} that received the keep-alive.
           * @param publishTime  the time the server published the keep-alive.
           */
          default void onKeepAliveNotification(UaSubscription subscription, DateTime publishTime) {}
  
          /**
           * A status change notification was received.
           *
           * @param subscription the {@link UaSubscription} that received the status change.
           * @param status       the new subscription status.
           */
          default void onStatusChangedNotification(UaSubscription subscription, StatusCode status) {}
  
          /**
           * Attempts to recover missed notification data have failed.
           * <p>
           * When a notification is missed a series of Republish requests are initiated to recover the missing data. If
           * republishing fails, or any of the notifications are no longer available, this callback will be invoked.
           *
           * @param subscription the subscription that missed notification data.
           */
          default void onNotificationDataLost(UaSubscription subscription) {}
  
          /**
           * A new {@link UaSession} was established, and upon attempting to transfer an existing subscription to this
           * new session, a failure occurred.
           * <p>
           * This subscription will be removed from {@link UaSubscriptionManager}'s bookkeeping. It must be re-created.
           *
           * @param subscription the {@link UaSubscription} that could not be transferred.
           * @param statusCode   the {@link StatusCode} for the transfer failure.
           */
          default void onSubscriptionTransferFailed(UaSubscription subscription, StatusCode statusCode) {}
  
          /**
           * The subscription watchdog timer has elapsed. The receiver of this callback should
           * consider deleting and re-creating this subscription or taking other appropriate action.
           * <p>
           * The timer elapses when 125% of the expected keep-alive interval has passed since receipt
           * of the last PublishResponse. The watchdog timer will not be restarted unless a new
           * PublishResponse for this subscription is received.
           * <p>
           * The expected keep-alive interval is {@code publishingInterval * keepAliveCount}
           * milliseconds.
           *
           * @param subscription the {@link UaSubscription} that has not received a response.
           */
          default void onSubscriptionWatchdogTimerElapsed(UaSubscription subscription) {}
  
      }
  
  }
  