PLCnext API Documentation 23.0.2.9
NonBlockingNotificationRegistration.hpp
1
2//
3// Copyright PHOENIX CONTACT Electronics GmbH
4//
6
7
8#pragma once
9
10
11#include "Arp/System/Nm/NonBlockingNotificationSendingAdapter.hpp"
12#include "Arp/System/Nm/NotificationRegistrationBase.hpp"
13
14
15namespace Arp { namespace System { namespace Nm
16{
17
18
31template<typename PayloadType>
33 : public NotificationRegistrationBase<NonBlockingNotificationRegistration<PayloadType>>
34{
35private:
36 using base_type =
38
39public:
40 using payload_type = PayloadType;
41
46
53 NonBlockingNotificationRegistration(const String& notificationName, const String& senderName,
54 Severity severity, INonBlockingNotificationSending& notificationSending);
55
56 NonBlockingNotificationRegistration(const String& notificationName, const String& senderName,
58
62
63
66
71 template<typename... Args>
73
78 template<typename... Args>
80 const DateTime& timestamp, Args&& ... args);
81
84
87
89 bool IsCompleted() const;
90
91private:
92 void Initialize();
93 void DisposeImpl() override;
94
95 bool IsNotificationNameIdValid() const;
96
97
98private:
99 INonBlockingNotificationSending* NotificationSending = nullptr;
100 Future<NotificationNameIdType> futureNotificationNameId;
101 Future<NotificationIdType> futureNotificationId;
102 Future<void> futureUnregister;
103
104 enum class State
105 {
106 Uninitialized,
107 RegisterCalled,
108 SendCalled,
109 UnregisterCalled
110 };
111 State state = State::Uninitialized;
112};
113
114
115template<typename PayloadType>
117 const String& notificationName, const String& senderName, Severity severity,
118 INonBlockingNotificationSending& notificationSending)
119 : base_type(notificationName, senderName, severity), NotificationSending(&notificationSending)
120{
121 this->Initialize();
122}
123
124template<typename PayloadType>
126 const String& notificationName, const String& senderName, Severity severity,
128 : base_type(notificationName, senderName, severity),
129 NotificationSending(adapter)
130{
131 this->Initialize();
132}
133
134
135template<typename PayloadType>
137 NonBlockingNotificationRegistration<PayloadType>&& other)
138 : base_type(std::move(other)),
139 NotificationSending(std::move(other.NotificationSending)),
140 futureNotificationNameId(std::move(other.futureNotificationNameId)),
141 futureNotificationId(std::move(other.futureNotificationId)),
142 futureUnregister(std::move(other.futureUnregister)),
143 state(std::move(other.state))
144{
145 other.NotificationSending = nullptr;
146 other.state = State::Uninitialized;
147}
148
149
150template<typename PayloadType>
151NonBlockingNotificationRegistration<PayloadType>::~NonBlockingNotificationRegistration()
152{
153 this->Dispose();
154}
155
156
157template<typename PayloadType>
158NonBlockingNotificationRegistration<PayloadType>& NonBlockingNotificationRegistration<PayloadType>::
159operator=(NonBlockingNotificationRegistration<PayloadType>&& other)
160{
161 if (this == &other)
162 {
163 return *this;
164 }
165
166 base_type::operator=(std::move(other));
167
168 this->NotificationSending = std::move(other.NotificationSending);
169 other.NotificationSending = nullptr;
170
171 this->futureNotificationNameId = std::move(other.futureNotificationNameId);
172 this->futureNotificationId = std::move(other.futureNotificationId);
173 this->futureUnregister = std::move(other.futureUnregister);
174
175 this->state = std::move(other.state);
176 other.state = State::Uninitialized;
177
178 return *this;
179}
180
181
182template<typename PayloadType>
183void NonBlockingNotificationRegistration<PayloadType>::Initialize()
184{
185 if ((this->NotificationSending != nullptr) && (!this->IsNotificationNameIdValid()))
186 {
187 auto* adapterPtr =
188 dynamic_cast<NonBlockingNotificationSendingAdapter*>(this->NotificationSending);
189 if (adapterPtr != nullptr)
190 {
191 adapterPtr->NonBlockingRegisterNotification(this->NotificationName, this->SenderName,
192 this->severity, this->GetPayloadTypeId(), this->futureNotificationNameId);
193 }
194 else
195 {
196 this->futureNotificationNameId =
197 this->NotificationSending->NonBlockingRegisterNotification(this->NotificationName,
198 this->SenderName, this->severity, this->GetPayloadTypeId());
199 }
200 this->state = State::RegisterCalled;
201 }
202}
203
204
205template<typename PayloadType>
206void NonBlockingNotificationRegistration<PayloadType>::DisposeImpl()
207{
208 if ((this->NotificationSending != nullptr) && this->IsNotificationNameIdValid())
209 {
210 auto* adapterPtr =
211 dynamic_cast<NonBlockingNotificationSendingAdapter*>(this->NotificationSending);
212 if (adapterPtr != nullptr)
213 {
214 adapterPtr->NonBlockingUnregisterNotification(
215 this->GetNotificationNameId(), this->futureUnregister);
216 }
217 else
218 {
219 this->futureUnregister = this->NotificationSending->NonBlockingUnregisterNotification(
220 this->GetNotificationNameId());
221 }
222 this->futureNotificationNameId = Future<NotificationNameIdType>();
223 this->futureNotificationId = Future<NotificationIdType>();
224 this->state = State::UnregisterCalled;
225
226 if (adapterPtr != nullptr)
227 {
228 delete this->NotificationSending;
229 }
230 this->NotificationSending = nullptr;
231 }
232}
233
234
235template<typename PayloadType>
236template<typename... Args>
238 Args&& ... args)
239{
240 return this->SendNotificationWithTimestamp(DateTime::Now(), std::forward<Args>(args)...);
241}
242
243
244template<typename PayloadType>
245template<typename... Args>
248 const DateTime& timestamp, Args&& ... args)
249{
250 if ((this->NotificationSending == nullptr) || (!this->IsNotificationNameIdValid()))
251 {
252 this->futureNotificationId = Future<NotificationIdType>();
253 }
254 else
255 {
256#ifndef ARP_CXX_COMPILER_MSC
257 // This optimization is not enabled on MSVC++. Capturing an c-string by value does not work.
258 auto adapterPtr =
259 dynamic_cast<NonBlockingNotificationSendingAdapter*>(this->NotificationSending);
260 if (adapterPtr != nullptr)
261 {
262 std::function<RawPayloadType()> createPayloadFunctor = [args...]()
263 {
264 return PayloadType{args...}.MoveOutRawPayload();
265 };
266 adapterPtr->NonBlockingSendNotification(this->futureNotificationNameId.GetValue(),
267 timestamp, std::move(createPayloadFunctor), this->futureNotificationId);
268 }
269 else
270#endif // #ifndef ARP_CXX_COMPILER_MSC
271 {
272 this->futureNotificationId = this->NotificationSending->NonBlockingSendNotification(
273 this->futureNotificationNameId.GetValue(), timestamp,
274 PayloadType{std::forward<Args>(args)...});
275 }
276 this->state = State::SendCalled;
277 }
278 return this->futureNotificationId;
279}
280
281
282template<class PayloadType>
285{
286 return this->futureNotificationNameId.GetValue();
287}
288
289
290template<class PayloadType>
292{
293 return this->futureNotificationId.GetValue();
294}
295
296
297template<class PayloadType>
299{
300 switch (this->state)
301 {
302 case State::Uninitialized:
303 return true;
304
305 case State::RegisterCalled:
306 return this->futureNotificationNameId.HasValue();
307
308 case State::SendCalled:
309 return this->futureNotificationId.HasValue();
310
311 case State::UnregisterCalled:
312 return this->futureUnregister.HasValue();
313
314 default:
315 return false;
316 }
317}
318
319
320template<class PayloadType>
322{
323 return this->futureNotificationNameId.HasValue() &&
324 this->futureNotificationNameId.GetValue().IsValid();
325}
326
327
328}}} // namespace Arp::System::Nm
The class contains date and time informations.
Definition: DateTime.hpp:45
static DateTime Now(void)
Gets the current time as DateTime, expressed as the UTC time.
Future object as proxy for return value an asynchronous function call
Definition: Future.hpp:191
Future object as proxy for return value an asynchronous function call
Definition: Future.hpp:114
Interface for non blocking sending of Notifications
Definition: INonBlockingNotificationSending.hpp:22
constexpr T GetValue() const noexcept
Returns the underlying value
Definition: IdType.hpp:94
Proxy object for a non-blocking NotificationRegistration
Definition: NonBlockingNotificationRegistration.hpp:34
NonBlockingNotificationRegistration(const String &notificationName, const String &senderName, Severity severity, INonBlockingNotificationSending &notificationSending)
Creates a NotificationRegistration
Definition: NonBlockingNotificationRegistration.hpp:116
Future< NotificationIdType > SendNotification(Args &&... args)
Sends a notification
Definition: NonBlockingNotificationRegistration.hpp:237
bool IsCompleted() const
Returns true if the last operation is completed
Definition: NonBlockingNotificationRegistration.hpp:298
Future< NotificationIdType > SendNotificationWithTimestamp(const DateTime &timestamp, Args &&... args)
Sends a notification with a specified timestamp
Definition: NonBlockingNotificationRegistration.hpp:247
NotificationNameIdType GetNotificationNameId() const override
Returns the NotificationNameId
Definition: NonBlockingNotificationRegistration.hpp:284
NonBlockingNotificationRegistration()=default
Creates an empty NotificationRegistration
NotificationIdType GetLastNotificationId() const
Returns the id of the last send Notification
Definition: NonBlockingNotificationRegistration.hpp:291
Adapter for INonBlockingNotificationSending with additional functions
Definition: NonBlockingNotificationSendingAdapter.hpp:25
Base class with common behavior of NotificationRegistration and NonBlockingNotificationRegistration
Definition: NotificationRegistrationBase.hpp:24
@ System
System components used by the System, Device, Plc or Io domains.
Severity
Enumeration of Severities for notifications
Definition: Severity.hpp:15
std::vector< Arp::System::Rsc::Services::RscVariant< RawPayloadTypeLength > > RawPayloadType
type for the internally transferred payloads
Definition: NotificationManagerTypes.hpp:34
Root namespace for the PLCnext API
Namespace of the C++ standard library