///////////////////////////////////////////////////////////////////// // StreamAdapter.cpp - sends Messages to Receiver via ostream // // // // Jim Fawcett, CSE776 - Design Patterns for Adapter Pattern // ///////////////////////////////////////////////////////////////////// /* * - This demo makes an adapter that supports sending Comm messages via * the std::ostream interface. * - You might expect that we would simply adapt std::ostream to use * Comm. * - That doesn't work because std::ostream doesn't provide any virtual * methods to override in the adapter. * - However, all standard streams use a std::streambuf or a class that * derives from std::streambuf, like std::filebuff and std::strstreambuff. * - std::streambuf does provide virtual methods, so we will adapt that * class to send Comm Messages, then build our ostream using the * adapted streambuf. * - That works, and has the benefit that all of the std::ostream output * methods and operators work by sending messages. * - This adapted stream can now be used by a logger to send logs to * remote machines, as well as log locally to unadapted streams. */ #include "../MsgPassingComm/Comm.h" #include "../Message/Message.h" #include #include namespace MsgPassingCommunication { Message makeMessage(EndPoint to, EndPoint from, const std::string& msg) { Message message(to, from); message.attribute("content", msg); return message; } /////////////////////////////////////////////////////////////////// // CommStreamBuf class // - class adapter // - adapts Comm to act like a std::streambuf class CommStreamBuf : public std::streambuf, private Comm { public: CommStreamBuf(EndPoint to, EndPoint from) : to_(to), from_(from), Comm(from) { start(); // start comm running } virtual ~CommStreamBuf() {} virtual std::streamsize xsputn(const char* s, std::streamsize count) override { // xsputn accepts characters from any of the ostream (non-virtual) methods Message msg = makeMessage(to_, from_, s); // make message using stream chars postMessage(msg); // post it to Comm return count; } void closeComm() { stop(); } private: EndPoint to_; EndPoint from_; }; /////////////////////////////////////////////////////////////////// // StreamAdapter class // - uses adapted streambuf in its internal inherited ostream class oCommStreamAdapter : private CommStreamBuf, public std::ostream { public: oCommStreamAdapter(EndPoint to, EndPoint from) : CommStreamBuf(to, from), std::ostream((CommStreamBuf*)this) {} void close() { closeComm(); } private: SocketSystem ss; // declaration needed for Comm's Socket Library }; } using namespace MsgPassingCommunication; void selfTest() { EndPoint ep("localhost",8080); Comm comm(ep,"testComm"); comm.start(); EndPoint to("localhost", 8080); EndPoint from("localhost", 8082); oCommStreamAdapter sa(to, from); // use ostream operator<< sa << "hi from client"; Message rcvd = comm.getMessage(); rcvd.show(); // use ostream write method sa.write("hi again from client", 20); rcvd = comm.getMessage(); rcvd.show(); } int main() { std::cout << "\n Demonstrating oCommStreamAdapter Sender"; std::cout << "\n ========================================="; EndPoint to("localhost", 8080); EndPoint from("localhost", 8081); oCommStreamAdapter sa(to, from); // use ostream operator<< std::string firstMsg = "hi from client"; std::cout << "\n sending 1st message \"" << firstMsg << "\" to receiver process"; sa << firstMsg; // use ostream write method std::string secondMsg = "hi again from client"; std::cout << "\n sending 2nd message \"" << secondMsg << "\" to receiver process"; sa.write(secondMsg.c_str(), secondMsg.length()); // tell receiver to shut down std::string thirdMsg = "quit"; std::cout << "\n requesting receiver process to shutdown with \"" << thirdMsg << "\""; sa << thirdMsg; std::cout << "\n\n"; std::cout << "\n press key to quit\n"; _getch(); sa.close(); return 0; }