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
18/*
19 * History:
20 07-Jan-2014 - TJF - Original version
21
22 * The above ID is for Doxygen, this one has the format ACMM is looking for.
23 * "@(#) $Id$"
24*/
25// Define to enable the MessageUserStream class - which does not work
26// on some systems. Currently disabled all the time until we understand
27// what is wrong in more detail.
28
29//#define D2_PROVIDE_MESSUSER_STREAM
30
31
32#include "drama/task.hh"
33#include "drama/entryinfo.hh"
34#include "drama/request.hh"
35#include "drama/action.hh"
36#include "drama/bulkdata.hh"
37#include "status.h"
38#include "DitsFix.h"
39#include "DitsMsgOut.h"
40#include <functional>
41namespace drama {
42
43 /*
44 * Forward declarations of interest.
45 */
46 class MessageHandler;
47 class Spawnable;
48
56 class SdsListToUserObj : public sds::PrintObjectCR {
57 private:
58 MessageHandler *_handler;
59 public:
61 SdsListToUserObj(MessageHandler *);
66 void Print(const std::string &line) const override;
67 };
68
74 using MessageHandlerPtr = std::shared_ptr<MessageHandler> ;
75
76
84 using MessageReceiveFunction = std::function<Request (MessageHandler *)> ;
85
111 class MessageHandler : public ActionHandler {
112 friend Spawnable; // Will invoke MessageEvent and InvokeActionEnd.
113 private:
114
115 /*
116 * MessageEvent is invoked when a message is received. Must invoke
117 * the sub-class's method.
118 */
119 Request MessageEvent(std::weak_ptr<Task> task, Action *action)
120 override ;
121 /*
122 * This is invoked when the action ends. Invokes the user override-able
123 * method ActionEnd().
124 */
125 void InvokeActionEnd(std::weak_ptr<Task> task, Action *action,
126 bool taskExiting,
127 StatusType actionEndStatus) override ;
128
129 /*
130 * These three are only valid during a call to MessageReceived() or
131 * ActionEnd().
132 */
133 std::weak_ptr<Task> _theTask;
134 Action *_action; // Detail of action (Should change to weak_ptr?)
135 EntryInfo _entryInfo; // Action entry details.
136
137 /*
138 * An object which can be used to list SDS structures via
139 * MessageUser.
140 */
141 SdsListToUserObj _sdsListToUserObj = this;
142 public:
143
147 MessageHandler() :
148 _action(nullptr) {
149
150 }
151
156 virtual ~MessageHandler();
157
162 MessageHandler& operator=(const MessageHandler &rhs) = delete;
167 MessageHandler(const MessageHandler &source) = delete;
168
180 private:
181 /*
182 * These can be marked private, as they are not meant to be
183 * called outside the object, just implemented by subclasses.
184 * Unfortunately, to get the documentation into our
185 * doxoygen pages, we need them to be protected.
186 */
187#ifdef RUNNING_DOXYGEN /* So that DOXYGEN will document the next two */
188 protected:
189#endif
190
210 virtual Request MessageReceived() = 0;
211
238 public:
252 virtual void MessageUser(const std::string &text) const;
253
254
276 template<typename... Types>
277 void MessageUser(const char *format, Types... args) {
278
279 /*
280 * Our approach is to write the output to a string, via
281 * SafePrintf(), then output that in one operation. Since
282 * std::ostream devices will then do the output in one operation.
283 */
284 std::stringstream sstrm;
286 MessageUser(sstrm.str());
287
288
289 }
290
291
301 virtual const sds::PrintObjectCR &SdsListToUser() const;
302
303
308 virtual const EntryInfo & GetEntry() {
309 return _entryInfo;
310 }
311
320 virtual std::shared_ptr<Task> GetTask() const {
321 return std::shared_ptr<Task>(_theTask);
322 }
323
340 void SendTrigger(const sds::Id &arg) const;
341
428 void SendBulkTrigger(BulkData *arg,
429 DitsTransIdType *transId,
430 bool isSds,
431 unsigned notifyBytes=1024*1024);
432
433
460 void SendBulkTrigger(BulkDataSds *arg,
461 DitsTransIdType *transId,
462 unsigned notifyBytes=1024*1024) {
463
464 SendBulkTrigger(arg, transId, true, notifyBytes);
465 }
466
467 std::string GetActionName() const {
468 if (!_action)
470 "Tried to GetActionName when not in action.");
471
472 return _action->GetActionName();
473 }
474
497 void SetReturnArg(const sds::Id &arg, bool copy=true) {
498
499 if (!_action)
501 "Tried to SetReturnArg when not in action.");
502
503
505 if (copy == false)
506 flag = DITS_ARG_NODELETE;
508 DitsPutArgument((SdsIdType)(arg), flag, &status);
509 if (status != STATUS__OK)
510 DramaTHROW(status,"Error when in call to DitsPutArgument()");
511 }
531 void SetReturnArg(sds::Id *arg) {
532 if (!_action)
534 "Tried to SetReturnArg when not in action.");
535
536 /*
537 * We need to work out what sds::Id would have
538 * done and use that to set our flag to DitsPutArgument()
539 */
542 bool free;
543 bool del;
544 bool readfree;
545 id = arg->COut(true, &free, &del, &readfree);
546 if (del)
547 flag = DITS_ARG_DELETE;
548 else if (readfree)
549 flag = DITS_ARG_READFREE;
550 else if (free)
551 flag = DITS_ARG_FREEID;
552
554 DitsPutArgument(id, flag, &status);
555 if (status != STATUS__OK)
556 DramaTHROW(status,"Error when in call to DitsPutArgument()");
557 }
571 virtual void PutObeyHandler(MessageHandlerPtr obj) {
572 if (!_action)
574 "Tried to change Obey handler when not in action.");
575 _action->PutObeyHandler(obj);
576 }
590 virtual void PutKickHandler(MessageHandlerPtr obj) {
591 if (!_action)
593 "Tried to change Kick handler when not in action.");
594 _action->PutKickHandler(obj);
595 }
596
630
631 protected:
639 void GrabEntryInfo() {
640 _entryInfo.SetFromDits();
641 }
642
643 };
644
655 class MessageHandlerViaFunctor : public MessageHandler {
656 private:
657 const MessageReceiveFunction _func; // The function.
658 public:
665 _func(func) {
674 return _func(this);
675 }
676 };
677
687
688
726 template <class T>
727 class MessageUserStreamBuf : public std::streambuf {
728
729 private:
730 T &_actionObj;
731 protected:
732 // Buffer for messages to output.
733 // Size is the maximum size of a DRAMA MsgOut message plus one
734 // for a null terminator.
735 char _buffer[MSG_C_LEN+1];
736
737 /*
738 * Buffer flush operation. Ensure the buffer is null terminated
739 * before calling MessageUser. Must return number sent and reset
740 * the buffer.
741 */
742 int flushBuffer() {
743 int num = pptr() - pbase();
744 *pptr() = '\0'; // Ensure null termination.
745 _actionObj.MessageUser(std::string(_buffer));
746 pbump(-num);
747 return num;
748 }
749
750 /*
751 * Invoked if adding a character would overflow the buffer.
752 * We Add it (since our constructor ensured there is sufficient
753 * space and then flush the buffer.
754 */
755 virtual int_type overflow(int_type c) override {
756 if (c != EOF)
757 {
758 // insert character into buffer
759 *pptr() = c;
760 pbump(1);
761 }
762 // flush the buffer
763 if (flushBuffer() == EOF)
764 {
765 return EOF;
766 }
767 return c;
768
769 }
770
771 virtual int sync() override {
772 if (flushBuffer() == EOF) {
773 return -1;
774 }
775 return 0;
776 }
777
778 public:
787 MessageUserStreamBuf(T &actionObj) : _actionObj(actionObj) {
788
789 /*
790 * Need to provide our buffer to the std::Streambuf base
791 * class. One character less to ensure the last character
792 * causes an overflow.
793 */
794 setp(_buffer, _buffer+(MSG_C_LEN-1));
795 }
800 virtual ~MessageUserStreamBuf() {
801 /*
802 * We want to output what is left, but any exception now
803 * (which may be caused by DRAMA failing to send the message
804 * for various reasons), if left uncaught, will cause the
805 * program to crash (can't throw from destructors), so
806 * catch any DRAMA exception and use stderr.
807 */
808 try
809 {
810 sync();
811 }
812 catch (drama::Exception &e)
813 {
814 fprintf(stderr,"DRAMA Exception thrown by drama::~MessageUserStreamBuf()\n");
815 fprintf(stderr,"%s\n", e.toString().c_str());
816 fprintf(stderr,"DRAMA Status = 0x%lX, %s\n",
817 static_cast<long int>(e.dramaStatus()),
818 e.dramaStatusStr().c_str());
819
820 }
821 }
822
823 }; //class MessageUserStreamBuf
824
825#ifdef D2_PROVIDE_LOG_STREAM // Currently disabled.
826// MessageUserStream not working under CLang, later versions. unclear why, but
827// appears related to copy/assignment. msgoutstream would
828// attempting to use a MessageStream
829
858 template <class T>
859 class MessageUserStream : public std::ostream {
860 private:
862 public:
872 /*
873 * Set the buffer address for ostream.
874 */
875 rdbuf(&_buf);
876 }
877
878 }; //class MessageUserStream.
879
880#endif
881
882} // namespace drama
883#endif
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:164
drama::Request MessageReceived() override
Invoke function.
Definition messagehandler.hh:700
MessageHandlerViaFunctor(const MessageReceiveFunction func)
Initialize object with the specified function, which meets the MessageReceiveFunction prototype.
Definition messagehandler.hh:691
This class is used to creating MessageHandler objects referring to functions.
Definition messagehandler.hh:682
virtual void PutObeyHandler(MessageHandlerPtr obj)
Put a message handler object for the next Obey reschedule event.
Definition messagehandler.hh:598
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:335
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:347
void GrabEntryInfo()
Fetch the DRAMA Entry information.
Definition messagehandler.hh:666
virtual void PutKickHandler(MessageHandlerPtr obj)
Put a message handler object for the next Kick event.
Definition messagehandler.hh:617
void SetReturnArg(sds::Id *arg)
Set the argument to be sent as part of the action completion message.
Definition messagehandler.hh:558
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:487
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:174
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:304
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:524
A class which implements a DRAMA Message Handler.
Definition messagehandler.hh:138
virtual ~MessageUserStreamBuf()
Destroy the MessgaeUserStream, any remaining output is sent.
Definition messagehandler.hh:827
MessageUserStreamBuf(T &actionObj)
Construct a MessageUserStreamBuf object.
Definition messagehandler.hh:814
Implement a streambuf sub-class that can write messages via the DRAMA MessageUser interface.
Definition messagehandler.hh:754
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:83
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:2323
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:93
void CreateRunDramaTask()
Create and run a DRAMA task, with standard exception handling.
Definition task.hh:1322
std::shared_ptr< MessageHandler > MessageHandlerPtr
This type is used for passing MessageHandler object addresses around.
Definition messagehandler.hh:101
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:111
The drama namespace contains all the classes, types etc of the DRAMA 2 implementation.
Definition drama.hh:93
DRAMA 2 include file - Request class definition.
DRAMA 2 include file - Task class definition.