The state table formally describes the operation of the Subscription. The following model of operations is described by this state table. This description applies when publishing is enabled or disabled for the Subscription.

After creation of the Subscription, the Server starts the publishing timer and restarts it whenever it expires. If the timer expires the number of times defined for the Subscription lifetime without having received a Subscription Service request from the Client, the Subscription assumes that the Client is no longer present, and terminates.

Clients send Publish requests to Servers to receive Notifications. Publish requests are not directed to any one Subscription and, therefore, may be used by any Subscription. Each contains acknowledgements for one or more Subscriptions. These acknowledgements are processed when the Publish request is received. The Server then queues the request in a queue shared by all Subscriptions, except in the following cases.

  1. The previous Publish response indicated that there were still more Notifications ready to be transferred and there were no more Publish requests queued to transfer them.
  2. The publishing timer of a Subscription expired and there were either Notifications to be sent or a keep-alive Message to be sent.

In these cases, the newly received Publish request is processed immediately by the first Subscription to encounter either case (a) or case (b).

Each time the publishing timer expires, it is immediately reset. If there are Notifications or a keep-alive Message to be sent, it de-queues and processes a Publish request. When a Subscription processes a Publish request, it accesses the queues of its MonitoredItems and de-queues its Notifications, if any. It returns these Notifications in the response, setting the moreNotifications flag if it was not able to return all available Notifications in the response.

If there were Notifications or a keep-alive Message to be sent but there were no Publish requests queued, the Subscription assumes that the Publish request is late and waits for the next Publish request to be received, as described in case (b).

If the Subscription is disabled when the publishing timer expires or if there are no Notifications available, it enters the keep-alive state and sets the keep-alive counter to its maximum value as defined for the Subscription.

While in the keep-alive state, it checks for Notifications each time the publishing timer expires. If one or more Notifications have been generated, a Publish request is de-queued and a NotificationMessage is returned in the response. However, if the publishing timer expires without a Notification becoming available, a Publish request is de-queued and a keep-alive Message is returned in the response. The Subscription then returns to the normal state of waiting for the publishing timer to expire again. If, in either of these cases, there are no Publish requests queued, the Subscription waits for the next Publish request to be received, as described in case (b).

The Subscription states are defined in Table 84.

Table 84 – Subscription States

State

Description

CLOSED

The Subscription has not yet been created or has terminated.

CREATING

The Subscription is being created.

NORMAL

The Subscription is cyclically checking for Notifications from its MonitoredItems. The keep-alive counter is not used in this state.

LATE

The publishing timer has expired and there are Notifications available or a keep-alive Message is ready to be sent, but there are no Publish requests queued. When in this state, the next Publish request is processed when it is received. The keep-alive counter is not used in this state.

KEEPALIVE

The Subscription is cyclically checking for Notifications from its MonitoredItems or for the keep-alive counter to count down to 0 from its maximum.

The state table is described in Table 85. The following rules and conventions apply.

  1. Events represent the receipt of Service requests and the occurrence internal Events, such as timer expirations.
  2. Service requests Events may be accompanied by conditions that test Service parameter values. Parameter names begin with a lower case letter.
  3. Internal Events may be accompanied by conditions that test state Variable values. State Variables are defined in 5.14.1.3. They begin with an upper case letter.
  4. Service request and internal Events may be accompanied by conditions represented by functions whose return value is tested. Functions are identified by “()” after their name. They are described in 5.14.1.4.
  5. When an Event is received, the first transition for the current state is located and the transitions are searched sequentially for the first transition that meets the Event or conditions criteria. If none are found, the Event is ignored.
  6. Actions are described by functions and state Variable manipulations.
  7. The LifetimeTimerExpires Event is triggered when its corresponding counter reaches zero.

Table 85 – Subscription State Table

#

Current State

Event/Conditions

Action

Next State

1

CLOSED

Receive CreateSubscription Request

CreateSubscription()

CREATING

2

CREATING

CreateSubscription fails

ReturnNegativeResponse()

CLOSED

3

CREATING

CreateSubscription succeeds

InitializeSubscription()

MessageSent = FALSE

ReturnResponse()

NORMAL

4

NORMAL

Receive Publish Request

&&

(

PublishingEnabled == FALSE

||

(PublishingEnabled == TRUE

&& MoreNotifications == FALSE)

)

DeleteAckedNotificationMsgs()

EnqueuePublishingReq()

NORMAL

5

NORMAL

Receive Publish Request

&& PublishingEnabled == TRUE

&& MoreNotifications == TRUE

ResetLifetimeCounter()

DeleteAckedNotificationMsgs()

ReturnNotifications()

MessageSent = TRUE

NORMAL

6

NORMAL

PublishingTimer Expires

&& PublishingReqQueued == TRUE

&& PublishingEnabled == TRUE

&& NotificationsAvailable == TRUE

ResetLifetimeCounter()

StartPublishingTimer()

DequeuePublishReq()

ReturnNotifications()

MessageSent = TRUE

NORMAL

7

NORMAL

PublishingTimer Expires

&& PublishingReqQueued == TRUE

&& MessageSent == FALSE

&&

(

PublishingEnabled == FALSE

||

(PublishingEnabled == TRUE

&& NotificationsAvailable == FALSE)

)

ResetLifetimeCounter()

StartPublishingTimer()

DequeuePublishReq()

ReturnKeepAlive()

MessageSent = TRUE

NORMAL

8

NORMAL

PublishingTimer Expires

&& PublishingReqQueued == FALSE

&&

(

MessageSent == FALSE

||

(PublishingEnabled == TRUE

&& NotificationsAvailable == TRUE)

)

StartPublishingTimer()

LATE

9

NORMAL

PublishingTimer Expires

&& MessageSent == TRUE

&&

(

PublishingEnabled == FALSE

||

(PublishingEnabled == TRUE

&& NotificationsAvailable == FALSE)

)

StartPublishingTimer()

ResetKeepAliveCounter()

KeepAliveCounter--

KEEPALIVE

10

LATE

Receive Publish Request

&& PublishingEnabled == TRUE

&& (NotificationsAvailable == TRUE

|| MoreNotifications == TRUE)

ResetLifetimeCounter()

DeleteAckedNotificationMsgs()

ReturnNotifications()

MessageSent = TRUE

NORMAL

11

LATE

Receive Publish Request

&&

(

PublishingEnabled == FALSE

||

(PublishingEnabled == TRUE

&& NotificationsAvailable == FALSE

&& MoreNotifications == FALSE)

)

ResetLifetimeCounter()

DeleteAckedNotificationMsgs()

ReturnKeepAlive()

MessageSent = TRUE

KEEPALIVE

12

LATE

PublishingTimer Expires

StartPublishingTimer()

LATE

13

KEEPALIVE

Receive Publish Request

DeleteAckedNotificationMsgs()

EnqueuePublishingReq()

KEEPALIVE

14

KEEPALIVE

PublishingTimer Expires

&& PublishingEnabled == TRUE

&& NotificationsAvailable == TRUE

&& PublishingReqQueued == TRUE

ResetLifetimeCounter()

StartPublishingTimer()

DequeuePublishReq()

ReturnNotifications()

MessageSent = TRUE

NORMAL

15

KEEPALIVE

PublishingTimer Expires

&& PublishingReqQueued == TRUE

&& KeepAliveCounter <= 1

&&

(

PublishingEnabled == FALSE

||

(PublishingEnabled == TRUE

&& NotificationsAvailable == FALSE

)

StartPublishingTimer()

DequeuePublishReq()

ReturnKeepAlive()

ResetKeepAliveCounter()

KEEPALIVE

16

KEEPALIVE

PublishingTimer Expires

&& KeepAliveCounter > 1

&&

(

PublishingEnabled == FALSE

||

(PublishingEnabled == TRUE

&& NotificationsAvailable == FALSE)

)

StartPublishingTimer()

KeepAliveCounter--

KEEPALIVE

17

KEEPALIVE

PublishingTimer Expires

&& PublishingReqQueued == FALSE

&&

(

KeepAliveCounter == 1

||

(KeepAliveCounter > 1

&& PublishingEnabled == TRUE

&& NotificationsAvailable == TRUE)

)

StartPublishingTimer()

LATE

18

NORMAL

|| LATE

|| KEEPALIVE

Receive ModifySubscription Request

&& SubscriptionAssignedToSession == TRUE

ResetLifetimeCounter()

UpdateSubscriptionParams()

ReturnResponse()

SAME

19

NORMAL

|| LATE

|| KEEPALIVE

Receive SetPublishingMode Request

&& SubscriptionAssignedToSession == TRUE

ResetLifetimeCounter()

SetPublishingEnabled()

MoreNotifications = FALSE

ReturnResponse()

SAME

20

NORMAL

|| LATE

|| KEEPALIVE

Receive Republish Request

&& RequestedMessageFound == TRUE

ResetLifetimeCounter()

ReturnResponse()

SAME

21

NORMAL

|| LATE

|| KEEPALIVE

Receive Republish Request

&& RequestedMessageFound == FALSE

ResetLifetimeCounter()

ReturnNegativeResponse()

SAME

22

NORMAL

|| LATE

|| KEEPALIVE

Receive TransferSubscriptions Request

&& SessionChanged() == FALSE

ResetLifetimeCounter()

ReturnNegativeResponse ()

SAME

23

NORMAL

|| LATE

|| KEEPALIVE

Receive TransferSubscriptions Request

&& SessionChanged() == TRUE

&& ClientValidated() ==TRUE

SetSession()

ResetLifetimeCounter()

ReturnResponse()

IssueStatusChangeNotification()

SAME

24

NORMAL

|| LATE

|| KEEPALIVE

Receive TransferSubscriptions Request

&& SessionChanged() == TRUE

&& ClientValidated() == FALSE

ReturnNegativeResponse()

SAME

25

NORMAL

|| LATE

|| KEEPALIVE

Receive DeleteSubscriptions Request

&& SubscriptionAssignedToSession ==TRUE

DeleteMonitoredItems()

DeleteClientPublReqQueue()

CLOSED

26

NORMAL

|| LATE

|| KEEPALIVE

Receive Subscription related Request

&& SubscriptionAssignedToSession ==FALSE

ResetLifetimeCounter()

ReturnNegativeResponse()

SAME

27

NORMAL

|| LATE

|| KEEPALIVE

LifetimeCounter == 1

The LifetimeCounter is decremented if PublishingTimer expires and PublishingReqQueued == FALSE

The LifetimeCounter is reset if PublishingReqQueued == TRUE.

DeleteMonitoredItems()

IssueStatusChangeNotification()

CLOSED