AAO DRAMA/DRAMA2 C++ Interface
DRAMA C++11 and later interface
messagehandler.hh
Go to the documentation of this file.
1#ifndef _DRAMA2_MESSAGEHANDLER_INC
2#define _DRAMA2_MESSAGEHANDLER_INC
14/*
15 * History:
16 07-Jan-2014 - TJF - Original version
17
18*/
19// Define to enable the MessageUserStream class - which does not work
20// on some systems. Currently disabled all the time until we understand
21// what is wrong in more detail.
22
23//#define D2_PROVIDE_MESSUSER_STREAM
24
25
26#include "drama/task.hh"
27#include "drama/entryinfo.hh"
28#include "drama/request.hh"
29#include "drama/action.hh"
30#include "drama/bulkdata.hh"
31#include "drama/fmt/format.h"
32#include "status.h"
33#include "DitsFix.h"
34#include "DitsMsgOut.h"
35#include <functional>
36namespace drama {
37
38 /*
39 * Forward declarations of interest.
40 */
41 class MessageHandler;
42 class Spawnable;
43
51 class SdsListToUserObj : public sds::PrintObjectCR {
52 private:
53 MessageHandler *_handler;
54 public:
56 SdsListToUserObj(MessageHandler *);
61 void Print(const std::string &line) const override;
62 };
63
69 using MessageHandlerPtr = std::shared_ptr<MessageHandler> ;
70
71
79 using MessageReceiveFunction = std::function<Request (MessageHandler *)> ;
80
114 class MessageHandler : public ActionHandler {
115 friend Spawnable; // Will invoke MessageEvent and InvokeActionEnd.
116 private:
117
118 /*
119 * MessageEvent is invoked when a message is received. Must invoke
120 * the sub-class's method.
121 */
122 Request MessageEvent(std::weak_ptr<Task> task, Action *action)
123 override ;
124 /*
125 * This is invoked when the action ends. Invokes the user override-able
126 * method ActionEnd().
127 */
128 void InvokeActionEnd(std::weak_ptr<Task> task, Action *action,
129 bool taskExiting,
130 StatusType actionEndStatus) override ;
131
132 /*
133 * These three are only valid during a call to MessageReceived() or
134 * ActionEnd().
135 */
136 std::weak_ptr<Task> _theTask;
137 Action *_action; // Detail of action (Should change to weak_ptr?)
138 EntryInfo _entryInfo; // Action entry details.
139
140 /*
141 * An object which can be used to list SDS structures via
142 * MessageUser.
143 */
144 SdsListToUserObj _sdsListToUserObj = this;
145 public:
146
150 MessageHandler() :
151 _action(nullptr) {
152
153 }
154
159 virtual ~MessageHandler();
160
165 MessageHandler& operator=(const MessageHandler &rhs) = delete;
170 MessageHandler(const MessageHandler &source) = delete;
171
183 private:
184 /*
185 * These can be marked private, as they are not meant to be
186 * called outside the object, just implemented by subclasses.
187 * Unfortunately, to get the documentation into our
188 * doxoygen pages, we need them to be protected.
189 */
190#ifdef RUNNING_DOXYGEN /* So that DOXYGEN will document the next two */
191 protected:
192#endif
193
213 virtual Request MessageReceived() = 0;
214
241 public:
264 virtual void MessageUser(const std::string &text) const;
265
293 template<typename... Types>
294#ifndef RUNNING_DOXYGEN
295 D2_FMT_DEPRECATED("Replace MessageUser() by MessageUserF(). See MessageUserF() page for details.")
296#endif
297 void MessageUser(const char *format, Types... args) {
298
299 /*
300 * Our approach is to write the output to a string, via
301 * SafePrintf(), then output that in one operation. Since
302 * std::ostream devices will then do the output in one operation.
303 */
304 std::stringstream sstrm;
306 MessageUser(sstrm.str());
307
308
309 }
376 template<typename... Args>
377 void MessageUserF(const fmt::format_string<Args...> fmt, Args&&... args) {
378
379 MessageUser(fmt::vformat(fmt.get(), fmt::make_format_args(args...)));
380
381 }
382
383
393 virtual const sds::PrintObjectCR &SdsListToUser() const;
394
395
400 virtual const EntryInfo & GetEntry() {
401 return _entryInfo;
402 }
403
412 virtual std::shared_ptr<Task> GetTask() const {
413 return std::shared_ptr<Task>(_theTask);
414 }
415
432 void SendTrigger(const sds::Id &arg) const;
433
520 void SendBulkTrigger(BulkData *arg,
521 DitsTransIdType *transId,
522 bool isSds,
523 unsigned notifyBytes=1024*1024);
524
525
552 void SendBulkTrigger(BulkDataSds *arg,
553 DitsTransIdType *transId,
554 unsigned notifyBytes=1024*1024) {
555
556 SendBulkTrigger(arg, transId, true, notifyBytes);
557 }
558
559 std::string GetActionName() const {
560 if (!_action)
562 "Tried to GetActionName when not in action.");
563
564 return _action->GetActionName();
565 }
566
589 void SetReturnArg(const sds::Id &arg, bool copy=true) {
590
591 if (!_action)
593 "Tried to SetReturnArg when not in action.");
594
595
597 if (copy == false)
598 flag = DITS_ARG_NODELETE;
600 DitsPutArgument((SdsIdType)(arg), flag, &status);
601 if (status != STATUS__OK)
602 DramaTHROW(status,"Error when in call to DitsPutArgument()");
603 }
623 void SetReturnArg(sds::Id *arg) {
624 if (!_action)
626 "Tried to SetReturnArg when not in action.");
627
628 /*
629 * We need to work out what sds::Id would have
630 * done and use that to set our flag to DitsPutArgument()
631 */
634 bool free;
635 bool del;
636 bool readfree;
637 id = arg->COut(true, &free, &del, &readfree);
638 if (del)
639 flag = DITS_ARG_DELETE;
640 else if (readfree)
641 flag = DITS_ARG_READFREE;
642 else if (free)
643 flag = DITS_ARG_FREEID;
644
646 DitsPutArgument(id, flag, &status);
647 if (status != STATUS__OK)
648 DramaTHROW(status,"Error when in call to DitsPutArgument()");
649 }
663 virtual void PutObeyHandler(MessageHandlerPtr obj) {
664 if (!_action)
666 "Tried to change Obey handler when not in action.");
667 _action->PutObeyHandler(obj);
668 }
682 virtual void PutKickHandler(MessageHandlerPtr obj) {
683 if (!_action)
685 "Tried to change Kick handler when not in action.");
686 _action->PutKickHandler(obj);
687 }
688
722
723 protected:
731 void GrabEntryInfo() {
732 _entryInfo.SetFromDits();
733 }
734
735 };
736
747 class MessageHandlerViaFunctor : public MessageHandler {
748 private:
749 const MessageReceiveFunction _func; // The function.
750 public:
757 _func(func) {
766 return _func(this);
767 }
768 };
769
779
780
818 template <class T>
819 class MessageUserStreamBuf : public std::streambuf {
820
821 private:
822 T &_actionObj;
823 protected:
824 // Buffer for messages to output.
825 // Size is the maximum size of a DRAMA MsgOut message plus one
826 // for a null terminator.
827 char _buffer[MSG_C_LEN+1];
828
829 /*
830 * Buffer flush operation. Ensure the buffer is null terminated
831 * before calling MessageUser. Must return number sent and reset
832 * the buffer.
833 */
834 int flushBuffer() {
835 int num = pptr() - pbase();
836 *pptr() = '\0'; // Ensure null termination.
837 _actionObj.MessageUser(std::string(_buffer));
838 pbump(-num);
839 return num;
840 }
841
842 /*
843 * Invoked if adding a character would overflow the buffer.
844 * We Add it (since our constructor ensured there is sufficient
845 * space and then flush the buffer.
846 */
847 virtual int_type overflow(int_type c) override {
848 if (c != EOF)
849 {
850 // insert character into buffer
851 *pptr() = c;
852 pbump(1);
853 }
854 // flush the buffer
855 if (flushBuffer() == EOF)
856 {
857 return EOF;
858 }
859 return c;
860
861 }
862
863 virtual int sync() override {
864 if (flushBuffer() == EOF) {
865 return -1;
866 }
867 return 0;
868 }
869
870 public:
879 MessageUserStreamBuf(T &actionObj) : _actionObj(actionObj) {
880
881 /*
882 * Need to provide our buffer to the std::Streambuf base
883 * class. One character less to ensure the last character
884 * causes an overflow.
885 */
886 setp(_buffer, _buffer+(MSG_C_LEN-1));
887 }
892 virtual ~MessageUserStreamBuf() {
893 /*
894 * We want to output what is left, but any exception now
895 * (which may be caused by DRAMA failing to send the message
896 * for various reasons), if left uncaught, will cause the
897 * program to crash (can't throw from destructors), so
898 * catch any DRAMA exception and use stderr.
899 */
900 try
901 {
902 sync();
903 }
904 catch (drama::Exception &e)
905 {
906 fprintf(stderr,"DRAMA Exception thrown by drama::~MessageUserStreamBuf()\n");
907 fprintf(stderr,"%s\n", e.toString().c_str());
908 fprintf(stderr,"DRAMA Status = 0x%lX, %s\n",
909 static_cast<long int>(e.dramaStatus()),
910 e.dramaStatusStr().c_str());
911
912 }
913 }
914
915 }; //class MessageUserStreamBuf
916
917#ifdef D2_PROVIDE_LOG_STREAM // Currently disabled.
918// MessageUserStream not working under CLang, later versions. unclear why, but
919// appears related to copy/assignment. msgoutstream would
920// attempting to use a MessageStream
921
950 template <class T>
951 class MessageUserStream : public std::ostream {
952 private:
954 public:
964 /*
965 * Set the buffer address for ostream.
966 */
967 rdbuf(&_buf);
968 }
969
970 }; //class MessageUserStream.
971
972#endif
973
974} // namespace drama
975#endif
976
DRAMA 2 include file - Bulk Data support.
Defines and optionally creates a shared memory section containing an SDS structure.
Definition bulkdata.hh:434
Defines and optionally creates a shared memory section.
Definition bulkdata.hh:121
void SetFromDits()
Grab the information of interest from DITS.
Definition entryinfo.hh:123
The EntryInfo class is used to access details about a DRAMA message event (and entry to an action).
Definition entryinfo.hh:106
An Exception class for exceptions thrown by DRAMA V2 classes.
Definition exception.hh:183
drama::Request MessageReceived() override
Invoke function.
Definition messagehandler.hh:792
MessageHandlerViaFunctor(const MessageReceiveFunction func)
Initialize object with the specified function, which meets the MessageReceiveFunction prototype.
Definition messagehandler.hh:783
This class is used to creating MessageHandler objects referring to functions.
Definition messagehandler.hh:774
void MessageUserF(const fmt::format_string< Args... > fmt, Args &&... args)
Use DRAMA to send a message to the user - format using fmt::format.
Definition messagehandler.hh:404
virtual void PutObeyHandler(MessageHandlerPtr obj)
Put a message handler object for the next Obey reschedule event.
Definition messagehandler.hh:690
virtual void ActionEnd(bool taskExiting, StatusType actionEndStatus)
Method Invoked when the action completes.
virtual const EntryInfo & GetEntry()
Return the action entry details.
Definition messagehandler.hh:427
virtual Request MessageReceived()=0
Method invoked by DRAMA to handle the message.
MessageHandler & operator=(const MessageHandler &rhs)=delete
Copy operator deleted.
MessageHandler(MessageHandler &&source)=default
Move assignment operator.
virtual std::shared_ptr< Task > GetTask() const
Returns a pointer to the task.
Definition messagehandler.hh:439
void GrabEntryInfo()
Fetch the DRAMA Entry information.
Definition messagehandler.hh:758
virtual void PutKickHandler(MessageHandlerPtr obj)
Put a message handler object for the next Kick event.
Definition messagehandler.hh:709
void SetReturnArg(sds::Id *arg)
Set the argument to be sent as part of the action completion message.
Definition messagehandler.hh:650
void SendBulkTrigger(BulkData *arg, DitsTransIdType *transId, bool isSds, unsigned notifyBytes=1024 *1024)
Send a bulk data trigger message to the parent action.
void SendBulkTrigger(BulkDataSds *arg, DitsTransIdType *transId, unsigned notifyBytes=1024 *1024)
Send a bulk data trigger message to the parent action.
Definition messagehandler.hh:579
virtual void MessageUser(const std::string &text) const
Use DRAMA to send a message to the user.
virtual ~MessageHandler()
MessageHandler destructor.
virtual void PutKickHandler(MessageReceiveFunction func)
Put a message handler function for the next Kick event.
MessageHandler()
Create a DRAMA action/message handler object.
Definition messagehandler.hh:177
virtual const sds::PrintObjectCR & SdsListToUser() const
Get a reference to an SDS printer object which can be used to list an SDS object using MessageUser.
virtual void PutObeyHandler(MessageReceiveFunction func)
Put a message handler function for the next Obey reschedule event.
MessageHandler & operator=(MessageHandler &&rhs)=default
Move operator.
void MessageUser(const char *format, Types... args)
Use DRAMA to send a message to the user - safe format.
Definition messagehandler.hh:324
void SendTrigger(const sds::Id &arg) const
Send a trigger message to the parent action.
MessageHandler(const MessageHandler &source)=delete
Assignment operator deleted.
void SetReturnArg(const sds::Id &arg, bool copy=true)
Set the argument to be sent as part of the action completion message.
Definition messagehandler.hh:616
A class which implements a DRAMA Message Handler.
Definition messagehandler.hh:141
virtual ~MessageUserStreamBuf()
Destroy the MessgaeUserStream, any remaining output is sent.
Definition messagehandler.hh:919
MessageUserStreamBuf(T &actionObj)
Construct a MessageUserStreamBuf object.
Definition messagehandler.hh:906
Implement a streambuf sub-class that can write messages via the DRAMA MessageUser interface.
Definition messagehandler.hh:846
Class used by Obey and Kick handlers to indicate rescheduling requirements.
Definition request.hh:78
SdsListToUserObj(MessageHandler *)
Constructor.
void Print(const std::string &line) const override
Prints one line of an SDS listing.
Object used to print SDS objects using MessageUser from MessageHandler objects.
Definition messagehandler.hh:78
A class which implements a Spawnable DRAMA Message Handler.
Definition spawnable.hh:84
virtual SdsIdType COut(const bool outlives, bool *const free=0, bool *const del=0, bool *const readfree=0)
Return this item as an SdsIdType for return to C code.
Definition sds.hh:2490
A C++ Interface to the handling SDS structures.
Definition sds.hh:428
Abstract class which is sub-classed to print SDS item listings.
Definition sds.hh:310
DRAMA 2 include file - implements a class providing access to details on an action entry.
#define DramaTHROW(status_, message_)
Throw a Drama exception.
Definition exception.hh:90
void CreateRunDramaTask()
Create and run a DRAMA task, with standard exception handling.
Definition task.hh:1339
std::shared_ptr< MessageHandler > MessageHandlerPtr
This type is used for passing MessageHandler object addresses around.
Definition messagehandler.hh:96
void SafePrintf(std::ostream &ostream, const char *str)
Safe formatted write to a stream.
Request SimpleExitAction(drama::MessageHandler *messageHandler)
A function which implements a simple exit action.
std::function< Request(MessageHandler *)> MessageReceiveFunction
Type used for functions specified to drama::MessageHandler::PutObeyHandler(), drama::MessageHandler::...
Definition messagehandler.hh:106
The drama namespace contains all the classes, types etc of the DRAMA 2 implementation.
Definition drama.hh:99
DRAMA 2 include file - Request class definition.
DRAMA 2 include file - Task class definition.