PLCnext API Documentation  21.0.0.35466
NonBlockingNotificationRegistration.hpp
1 //
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 
15 namespace Arp { namespace System { namespace Nm
16 {
17 
18 
31 template<typename PayloadType>
33  : public NotificationRegistrationBase<NonBlockingNotificationRegistration<PayloadType>>
34 {
35 private:
36  using base_type =
38 
39 public:
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 
61 
63 
66  const NonBlockingNotificationRegistration&) = delete;
67 
72  template<typename... Args>
74 
79  template<typename... Args>
81  const DateTime& timestamp, Args&& ... args);
82 
85 
88 
90  bool IsCompleted() const;
91 
92 private:
93  void Initialize();
94  void DisposeImpl() override;
95 
96  bool IsNotificationNameIdValid() const;
97 
98 
99 private:
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 
116 template<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 
125 template<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 
136 template<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 
151 template<typename PayloadType>
153 {
154  this->Dispose();
155 }
156 
157 
158 template<typename PayloadType>
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 
183 template<typename PayloadType>
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 
206 template<typename PayloadType>
208 {
209  if (this->NotificationSending != nullptr && this->IsNotificationNameIdValid())
210  {
211  auto adapterPtr =
212  dynamic_cast<NonBlockingNotificationSendingAdapter*>(this->NotificationSending);
213  if (adapterPtr != nullptr)
214  {
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 
236 template<typename PayloadType>
237 template<typename... Args>
239  Args&& ... args)
240 {
241  return this->SendNotificationWithTimestamp(DateTime::Now(), std::forward<Args>(args)...);
242 }
243 
244 
245 template<typename PayloadType>
246 template<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 
283 template<class PayloadType>
286 {
287  return this->futureNotificationNameId.GetValue();
288 }
289 
290 
291 template<class PayloadType>
293 {
294  return this->futureNotificationId.GetValue();
295 }
296 
297 
298 template<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 
321 template<class PayloadType>
323 {
324  return this->futureNotificationNameId.HasValue() &&
325  this->futureNotificationNameId.GetValue().IsValid();
326 }
327 
328 
329 }}} // namespace Arp::System::Nm
Interface for non blocking sending of Notifications
Definition: INonBlockingNotificationSending.hpp:21
NotificationNameIdType GetNotificationNameId() const override
Returns the NotificationNameId
Definition: NonBlockingNotificationRegistration.hpp:285
Future< void > NonBlockingUnregisterNotification(NotificationNameIdType notificationNameId) override
Unregisters a Nototification (non-blocking)
Future object as proxy for return value an asynchronous function call
Definition: Future.hpp:191
bool IsCompleted() const
Returns true if the last operation is completed
Definition: NonBlockingNotificationRegistration.hpp:299
The class contains date and time informations.
Definition: DateTime.hpp:44
Proxy object for a non-blocking NotificationRegistration
Definition: NonBlockingNotificationRegistration.hpp:32
NonBlockingNotificationRegistration()=default
Creates an empty NotificationRegistration
Severity
Enumeration of Severities for notifications
Definition: Severity.hpp:15
Root namespace for the PLCnext API
Base class with common behavior of NotificationRegistration and NonBlockingNotificationRegistration
Definition: NotificationRegistrationBase.hpp:19
NotificationIdType GetLastNotificationId() const
Returns the id of the last send Notification
Definition: NonBlockingNotificationRegistration.hpp:292
Future< NotificationIdType > SendNotificationWithTimestamp(const DateTime &timestamp, Args &&... args)
Sends a notification with a specified timestamp
Definition: NonBlockingNotificationRegistration.hpp:248
Future< NotificationIdType > SendNotification(Args &&... args)
Sends a notification
Definition: NonBlockingNotificationRegistration.hpp:238
Future object as proxy for return value an asynchronous function call
Definition: Future.hpp:114
Future< NotificationNameIdType > NonBlockingRegisterNotification(const String &notificationName, const String &senderName, Severity severity, PayloadTypeIdType payloadTypeId) override
Registers a new Notification (non-blocking)
System components used by the System, Device, Plc or Io domains.
Adapter for INonBlockingNotificationSending with additional functions
Definition: NonBlockingNotificationSendingAdapter.hpp:24
Representation of an unique id
Definition: IdType.hpp:28