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