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.
- 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.
- 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.
- Events represent the receipt of Service requests and the occurrence internal Events, such as timer expirations.
- Service requests Events may be accompanied by conditions that test Service parameter values. Parameter names begin with a lower case letter.
- Internal Events may be accompanied by conditions that test state Variable values. State Variables are defined in 5.13.1.3. They begin with an upper case letter.
- 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.13.1.4.
- 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.
- Actions are described by functions and state Variable manipulations.
- 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 |
ResetLifetimeCounter() UpdateSubscriptionParams() ReturnResponse() |
SAME |
19 |
NORMAL || LATE || KEEPALIVE |
Receive SetPublishingMode Request |
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 && SubscriptionAssignedToClient ==TRUE |
DeleteMonitoredItems() DeleteClientPublReqQueue() |
CLOSED |
26 |
NORMAL || LATE || KEEPALIVE |
Receive DeleteSubscriptions Request && SubscriptionAssignedToClient ==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 |