diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-06-10 22:47:14 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-06-10 22:47:14 (GMT) |
commit | 6f56474450b7c54f2c95b5dea6a7a42623141649 (patch) | |
tree | 420c52085d8cf778360c09baf9722b21d01259da /apps/w3c-mmi | |
parent | a154682fc1b25581742d38dd5fe9aa06ede167b7 (diff) | |
download | uscxml-6f56474450b7c54f2c95b5dea6a7a42623141649.zip uscxml-6f56474450b7c54f2c95b5dea6a7a42623141649.tar.gz uscxml-6f56474450b7c54f2c95b5dea6a7a42623141649.tar.bz2 |
W3C MMI Architecture framework
Diffstat (limited to 'apps/w3c-mmi')
-rw-r--r-- | apps/w3c-mmi/MMIEventServlet.cpp | 210 | ||||
-rw-r--r-- | apps/w3c-mmi/MMIEventServlet.h | 59 | ||||
-rw-r--r-- | apps/w3c-mmi/im/MMISessionManager.cpp | 257 | ||||
-rw-r--r-- | apps/w3c-mmi/im/MMISessionManager.h | 81 | ||||
-rw-r--r-- | apps/w3c-mmi/im/uscxml-interaction-manager.cpp | 182 | ||||
-rw-r--r-- | apps/w3c-mmi/mc/uscxml-modality-component.cpp | 191 |
6 files changed, 980 insertions, 0 deletions
diff --git a/apps/w3c-mmi/MMIEventServlet.cpp b/apps/w3c-mmi/MMIEventServlet.cpp new file mode 100644 index 0000000..5ee1807 --- /dev/null +++ b/apps/w3c-mmi/MMIEventServlet.cpp @@ -0,0 +1,210 @@ +#include "MMIEventServlet.h" +#include <uscxml/NameSpacingParser.h> + +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#endif + +#include "uscxml/Message.h" +#include <iostream> +#include <event2/dns.h> +#include <event2/buffer.h> +#include <event2/keyvalq_struct.h> + +#include <string.h> + +#include <io/uri.hpp> +#include <glog/logging.h> + +#ifndef _WIN32 +#include <netdb.h> +#include <arpa/inet.h> +#endif + +#define MMI_HTTP_EVENT_CASE(type) \ +else if (boost::iequals(mmiEvent.getLocalName(), #type)) { \ + monIter = _monitors.begin(); \ + while(monIter != _monitors.end()) { \ + (*monIter)->received(type::fromXML(mmiDoc)); \ + monIter++; \ + } \ +} + +namespace uscxml { + + using namespace Arabica::DOM; + + MMIEventServlet::MMIEventServlet(const std::string& path) : _path(path) { + // register at http server + bool success = HTTPServer::registerServlet(_path, this); + assert(success); + } + + MMIEventServlet::~MMIEventServlet() { + HTTPServer* httpServer = HTTPServer::getInstance(); + httpServer->unregisterServlet(this); + } + + void MMIEventServlet::send(const MMIEvent& mmiEvent) { + URL url(mmiEvent.target); + url.addMonitor(this); + + std::stringstream content; + content << mmiEvent.toXML(); + url.setOutContent(content.str()); + url.download(); + + } + + void MMIEventServlet::httpRecvRequest(const HTTPServer::Request& req) { + + // is this a request from a HTML browser? + + + NameSpacingParser* parser = NameSpacingParser::fromXML(req.data.compound.at("content").atom); + if (!parser) { + evhttp_send_error(req.curlReq, 402, NULL); + return; + } + + Document<std::string> mmiDoc = parser->getDocument(); + std::cout << mmiDoc.getNamespaceURI() << std::endl; + Node<std::string> mmiEvent = mmiDoc.getFirstChild(); + // get the first element + while (mmiEvent && mmiEvent.getNodeType() != Node_base::ELEMENT_NODE) { + mmiEvent = mmiEvent.getNextSibling(); + } + // get the contained message + if (boost::iequals(mmiEvent.getLocalName(), "mmi")) { + mmiEvent = mmiEvent.getFirstChild(); + while (mmiEvent && mmiEvent.getNodeType() != Node_base::ELEMENT_NODE) { + mmiEvent = mmiEvent.getNextSibling(); + } + } + std::cout << mmiEvent << std::endl; + + if (!mmiEvent) { + evhttp_send_error(req.curlReq, 402, NULL); + return; + } + + std::set<MMIEventReceiver*>::iterator monIter; + if (false) {} + MMI_HTTP_EVENT_CASE(NewContextRequest) + MMI_HTTP_EVENT_CASE(NewContextResponse) + MMI_HTTP_EVENT_CASE(PrepareRequest) + MMI_HTTP_EVENT_CASE(PrepareResponse) + MMI_HTTP_EVENT_CASE(StartRequest) + MMI_HTTP_EVENT_CASE(StartResponse) + MMI_HTTP_EVENT_CASE(DoneNotification) + MMI_HTTP_EVENT_CASE(CancelRequest) + MMI_HTTP_EVENT_CASE(CancelResponse) + MMI_HTTP_EVENT_CASE(PauseRequest) + MMI_HTTP_EVENT_CASE(PauseResponse) + MMI_HTTP_EVENT_CASE(ResumeRequest) + MMI_HTTP_EVENT_CASE(ResumeResponse) + MMI_HTTP_EVENT_CASE(ExtensionNotification) + MMI_HTTP_EVENT_CASE(ClearContextRequest) + MMI_HTTP_EVENT_CASE(ClearContextResponse) + MMI_HTTP_EVENT_CASE(StatusRequest) + MMI_HTTP_EVENT_CASE(StatusResponse) + else { + LOG(ERROR) << "Unknown MMI Event"; + evhttp_send_error(req.curlReq, 402, NULL); + return; + } + + evhttp_send_reply(req.curlReq, 204, NULL, NULL); + +#if 0 + Event reqEvent = req; + reqEvent.type = Event::EXTERNAL; + bool scxmlStructFound = false; + + if (reqEvent.data.compound["header"].compound.find("Content-Type") != reqEvent.data.compound["header"].compound.end() && + boost::iequals(reqEvent.data.compound["header"].compound["Content-Type"].atom, "application/x-www-form-urlencoded")) { + std::stringstream ss(reqEvent.data.compound["content"].atom); + std::string term; + while(std::getline(ss, term, '&')) { + size_t split = term.find_first_of("="); + if (split != std::string::npos) { + std::string key = evhttp_decode_uri(term.substr(0, split).c_str()); + std::string value = evhttp_decode_uri(term.substr(split + 1).c_str()); + if (boost::iequals(key, "_scxmleventname")) { + reqEvent.name = value; + } else if (boost::iequals(key, "content")) { + reqEvent.initContent(value); + } else { + reqEvent.data.compound[key] = value; + reqEvent.params.insert(std::make_pair(key, value)); + } + } else { + // this is most likely wrong + reqEvent.content = evhttp_decode_uri(term.c_str()); + } + } + } else { + if (reqEvent.data.compound["header"].compound.find("_scxmleventstruct") != reqEvent.data.compound["header"].compound.end()) { + // TODO: this looses all other information + reqEvent = Event::fromXML(evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventstruct"].atom.c_str())); + scxmlStructFound = true; + } + if (reqEvent.data.compound["header"].compound.find("_scxmleventname") != reqEvent.data.compound["header"].compound.end()) { + reqEvent.name = evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventname"].atom.c_str()); + } + } + std::map<std::string, Data>::iterator headerIter = reqEvent.data.compound["header"].compound.begin(); + while(headerIter != reqEvent.data.compound["header"].compound.end()) { + reqEvent.data.compound[headerIter->first] = Data(evhttp_decode_uri(headerIter->second.atom.c_str()), Data::VERBATIM); + headerIter++; + } + + + /// test532 + if (reqEvent.name.length() == 0) + reqEvent.name = "http." + req.data.compound.at("type").atom; + + if (!scxmlStructFound) { + // get content into event + reqEvent.data.compound["content"] = Data(req.content, Data::VERBATIM); + } + + evhttp_send_reply(req.curlReq, 200, "OK", NULL); +#endif + } + + void MMIEventServlet::downloadStarted(const URL& url) {} + + void MMIEventServlet::downloadCompleted(const URL& url) { + std::map<std::string, std::pair<URL, SendRequest> >::iterator reqIter = _sendRequests.begin(); + while(reqIter != _sendRequests.end()) { + if (reqIter->second.first == url) { + _sendRequests.erase(reqIter); + return; + } + reqIter++; + } + assert(false); + } + + void MMIEventServlet::downloadFailed(const URL& url, int errorCode) { + + std::map<std::string, std::pair<URL, SendRequest> >::iterator reqIter = _sendRequests.begin(); + while(reqIter != _sendRequests.end()) { + if (reqIter->second.first == url) { + Event failEvent; + failEvent.name = "error.communication"; +// returnEvent(failEvent); + + _sendRequests.erase(reqIter); + return; + } + reqIter++; + } + assert(false); + + } + + +}
\ No newline at end of file diff --git a/apps/w3c-mmi/MMIEventServlet.h b/apps/w3c-mmi/MMIEventServlet.h new file mode 100644 index 0000000..10adbc3 --- /dev/null +++ b/apps/w3c-mmi/MMIEventServlet.h @@ -0,0 +1,59 @@ +#ifndef MMIEVENTSERVLET_H_92WSR1SU +#define MMIEVENTSERVLET_H_92WSR1SU + + +#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h" +#include "uscxml/server/HTTPServer.h" +#include "uscxml/Interpreter.h" +#include "uscxml/Factory.h" +#ifndef _WIN32 +#include <sys/time.h> +#endif + +#include <event2/http.h> +#include <event2/http_struct.h> + +#include <uscxml/plugins/ioprocessor/modality/MMIMessages.h> + +namespace uscxml { + + class MMIEventServlet : public HTTPServlet, public URLMonitor, public MMIEventSender { + public: + MMIEventServlet(const std::string& path); + virtual ~MMIEventServlet(); + + void addMonitor(MMIEventReceiver* mmiMonitor) { + _monitors.insert(mmiMonitor); + } + void removeMonitor(MMIEventReceiver* mmiMonitor) { + _monitors.erase(mmiMonitor); + } + + /// HTTPServlet + void httpRecvRequest(const HTTPServer::Request& req); + void setURL(const std::string& url) { + _url = url; + } + std::string getURL() { return _url; } + + bool canAdaptPath() { + return false; + } + + // URLMonitor + void downloadStarted(const URL& url); + void downloadCompleted(const URL& url); + void downloadFailed(const URL& url, int errorCode); + + // MMIEventSender + virtual void send(const MMIEvent& mmiEvent); + + protected: + std::string _url; + std::string _path; + std::map<std::string, std::pair<URL, SendRequest> > _sendRequests; + std::set<MMIEventReceiver*> _monitors; + }; +} + +#endif /* end of include guard: MMIEVENTSERVLET_H_92WSR1SU */ diff --git a/apps/w3c-mmi/im/MMISessionManager.cpp b/apps/w3c-mmi/im/MMISessionManager.cpp new file mode 100644 index 0000000..768a8a1 --- /dev/null +++ b/apps/w3c-mmi/im/MMISessionManager.cpp @@ -0,0 +1,257 @@ +#include "MMISessionManager.h" +#include <uscxml/NameSpacingParser.h> +#include <uscxml/concurrency/tinythread.h> + +#include <io/uri.hpp> +#include <glog/logging.h> + +namespace uscxml { + + using namespace Arabica::DOM; + + MMISessionManager::MMISessionManager(Interpreter interpreter) : _protoInterpreter(interpreter) { + bool success = HTTPServer::registerServlet(interpreter.getName(), this); + assert(success); + _factory = new Factory(Factory::getInstance()); + _factory->registerIOProcessor(new MMIIOProcessor(this)); + } + + MMISessionManager::~MMISessionManager() { + HTTPServer* httpServer = HTTPServer::getInstance(); + httpServer->unregisterServlet(this); + } + + void MMISessionManager::setupHTMLClient(const HTTPServer::Request& req) { + // open template file + HTTPServer::Reply reply(req); + URL templateURL(_protoInterpreter.getBaseURI().asString() + "/templates/mc-html.html"); + templateURL.download(true); + std::string templateContent = templateURL.getInContent(); + boost::replace_all(templateContent, "${im.url}", _url); + reply.content = templateContent; + HTTPServer::reply(reply); + } + + void MMISessionManager::httpRecvRequest(const HTTPServer::Request& req) { + // is this an initial request from an HTML MC? + if (!req.data["query"]["token"] && // no token in query + boost::iequals(req.data["type"].atom, "get") && // request type is GET + boost::icontains(req.data["header"]["Accept"].atom, "text/html") && // accepts html + req.content.length() == 0) { // no content + setupHTMLClient(req); + return; + } + + // is this a comet longpolling request? + if (req.data["query"]["token"] && + boost::iequals(req.data["type"].atom, "get")) { + std::string token = req.data["query"]["token"].atom; + if (_tokens.find(token) != _tokens.end()) { + MMISessionManager::CometMMISession* comet = static_cast<MMISessionManager::CometMMISession*>(_tokens[token]); + comet->longPoll(req); + return; + } + } + + // assume that there is an mmi event inside + NameSpacingParser* parser = NameSpacingParser::fromXML(req.data.compound.at("content").atom); + if (!parser) { + evhttp_send_error(req.curlReq, 204, NULL); + return; + } + + Node<std::string> mmiEvent = MMIEvent::getEventNode(parser->getDocument()); + if (!mmiEvent) { + evhttp_send_error(req.curlReq, 204, NULL); + return; + } + + switch(MMIEvent::getType(mmiEvent)) { + case MMIEvent::NEWCONTEXTREQUEST: { + received(NewContextRequest::fromXML(mmiEvent), req.data["query"]["token"].atom); + evhttp_send_error(req.curlReq, 204, NULL); + break; + } + case MMIEvent::EXTENSIONNOTIFICATION: { + received(ExtensionNotification::fromXML(mmiEvent)); + evhttp_send_error(req.curlReq, 204, NULL); + break; + } + default: { + LOG(ERROR) << "Unknown MMI Event"; + evhttp_send_error(req.curlReq, 204, NULL); + break; + } + } + } + + void MMISessionManager::received(const ExtensionNotification& mmiEvent) { + assert(_sessions.find(mmiEvent.context) != _sessions.end()); + _sessions[mmiEvent.context]->_interpreter.receive(mmiEvent); + } + + void MMISessionManager::received(const NewContextRequest& mmiEvent, const std::string& token) { + + // copy DOM from prototype instance + Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + Arabica::DOM::Document<std::string> newDOM = domFactory.createDocument("", "", 0); + newDOM.appendChild(newDOM.importNode(_protoInterpreter.getDocument().getDocumentElement(), true)); + + // instantiate new interpreter and name it after the context + std::string contextId = Interpreter::getUUID(); + Interpreter interpreter = Interpreter::fromDOM(newDOM); + interpreter.setFactory(_factory); + interpreter.setName(contextId); + interpreter.setNameSpaceInfo(_protoInterpreter.getNameSpaceInfo()); + interpreter.setBaseURI(_protoInterpreter.getBaseURI().asString()); + + MMISession* session; + + if (token.length() > 0) { + session = new MMISessionManager::CometMMISession(); + static_cast<MMISessionManager::CometMMISession*>(session)->_token = token; + _tokens[token] = session; + } else { + // todo handle other cases + session = new MMISessionManager::CometMMISession(); + } + session->_interpreter = interpreter; + + // save interpreter + _sessions[contextId] = session; + + interpreter.start(); + interpreter.receive(mmiEvent); + + } + + void MMISessionManager::received(const NewContextResponse& mmiEvent) { + } + + void MMISessionManager::send(const std::string& name, const SendRequest& req) { + assert(_sessions.find(name) != _sessions.end()); + _sessions[name]->send(req); + } + + void MMISessionManager::CometMMISession::send(const SendRequest& req) { + tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); + if (!_longPollingReq) { + _outQueue.push_back(req); + return; + } + + if (req.dom) { + std::stringstream ss; + Node<std::string> mmiEvent = MMIEvent::getEventNode(req.dom); + HTTPServer::Reply reply(_longPollingReq); + + switch (MMIEvent::getType(mmiEvent)) { + case MMIEvent::NEWCONTEXTRESPONSE: { + NewContextResponse response = NewContextResponse::fromXML(mmiEvent); + ss << response.toXML(); + reply.content = ss.str(); + break; + } + case MMIEvent::STARTREQUEST: { + StartRequest request = StartRequest::fromXML(mmiEvent); + std::cout << mmiEvent << std::endl; + ss << request.toXML(); + reply.content = ss.str(); + break; + } + default: + break; + } + reply.headers["Content-Type"] = "application/xml"; + HTTPServer::reply(reply); + _longPollingReq = HTTPServer::Request(); + } + } + + void MMISessionManager::CometMMISession::receive(const Arabica::DOM::Node<std::string>& msg) { + + } + + void MMISessionManager::CometMMISession::longPoll(const HTTPServer::Request& req) { + tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); + if (_longPollingReq) + evhttp_send_error(_longPollingReq.curlReq, 204, NULL); + _longPollingReq = req; + if (!_outQueue.empty()) { + send(_outQueue.front()); + _outQueue.pop_front(); + } + } + + boost::shared_ptr<IOProcessorImpl> MMISessionManager::MMIIOProcessor::create(InterpreterImpl* interpreter) { + boost::shared_ptr<IOProcessorImpl> ioProc = boost::shared_ptr<IOProcessorImpl>(new MMISessionManager::MMIIOProcessor(_sessionManager)); + return ioProc; + } + + Data MMISessionManager::MMIIOProcessor::getDataModelVariables() { + Data data; + return data; + } + + void MMISessionManager::MMIIOProcessor::send(const SendRequest& req) { + SendRequest reqCopy(req); + + if (req.dom) { + Arabica::DOM::Node<std::string> mmiEvent = MMIEvent::getEventNode(req.dom); + if (!mmiEvent || !mmiEvent.getNodeType() == Node_base::ELEMENT_NODE) + return; + + Arabica::DOM::Element<std::string> mmiElem = Arabica::DOM::Element<std::string>(mmiEvent); + switch (MMIEvent::getType(mmiEvent)) { + case MMIEvent::STARTRESPONSE: + case MMIEvent::PREPARERESPONSE: + case MMIEvent::PAUSERESPONSE: + case MMIEvent::RESUMERESPONSE: + case MMIEvent::CANCELRESPONSE: + case MMIEvent::DONENOTIFICATION: + case MMIEvent::NEWCONTEXTRESPONSE: + case MMIEvent::CLEARCONTEXTRESPONSE: + case MMIEvent::STATUSRESPONSE: { + // all of the above have a status + if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "Status")) { + mmiElem.setAttributeNS(MMIEvent::nameSpace, "Status", "Success"); + } + } + case MMIEvent::PAUSEREQUEST: + case MMIEvent::RESUMEREQUEST: + case MMIEvent::CANCELREQUEST: + case MMIEvent::CLEARCONTEXTREQUEST: + case MMIEvent::STATUSREQUEST: { + // all of the above have a context + if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "Context")) { + mmiElem.setAttributeNS(MMIEvent::nameSpace, "Context", _interpreter->getName()); + } + } + default: { + if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "Source")) { + mmiElem.setAttributeNS(MMIEvent::nameSpace, "Source", _sessionManager->getURL()); + } + if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "Target")) { + if (boost::starts_with(_interpreter->getCurrentEvent().name, "mmi.")) { + mmiElem.setAttributeNS(MMIEvent::nameSpace, "Target", _interpreter->getCurrentEvent().origin); + } + } + if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "RequestID")) { + if (boost::starts_with(_interpreter->getCurrentEvent().name, "mmi.")) { + mmiElem.setAttributeNS(MMIEvent::nameSpace, "RequestID", _interpreter->getCurrentEvent().sendid); + } + } + } + } + + if (MMIEvent::getType(mmiEvent) == MMIEvent::EXTENSIONNOTIFICATION && !mmiElem.hasAttribute("Name") && req.name.length() > 0) { + mmiElem.setAttribute("Name", req.name); + } + // use session mgr to dispatch to session + + _sessionManager->send(_interpreter->getName(), reqCopy); + } + + } + +}
\ No newline at end of file diff --git a/apps/w3c-mmi/im/MMISessionManager.h b/apps/w3c-mmi/im/MMISessionManager.h new file mode 100644 index 0000000..2ca3d0c --- /dev/null +++ b/apps/w3c-mmi/im/MMISessionManager.h @@ -0,0 +1,81 @@ +#ifndef MMISESSIONMANAGER_H_IHDWUAKD +#define MMISESSIONMANAGER_H_IHDWUAKD + +#include <uscxml/Interpreter.h> +#include <deque> +#include "../MMIEventServlet.h" + +namespace uscxml { + class MMISessionManager : public HTTPServlet { + public: + MMISessionManager(Interpreter interpreter); + ~MMISessionManager(); + + class MMISession { + public: + Interpreter _interpreter; + tthread::recursive_mutex _mutex; + virtual void send(const SendRequest& req) = 0; + virtual void receive(const Arabica::DOM::Node<std::string>& msg) = 0; + }; + + class CometMMISession : public MMISession { + public: + HTTPServer::Request _request; + std::deque<SendRequest> _outQueue; + HTTPServer::Request _longPollingReq; + std::string _token; + + void send(const SendRequest& req); + void receive(const Arabica::DOM::Node<std::string>& msg); + void longPoll(const HTTPServer::Request& req); + }; + + class MMIIOProcessor : public IOProcessorImpl { + public: + MMIIOProcessor(MMISessionManager* sessionManager) : _sessionManager(sessionManager) {} + + // IOProcessorImpl + virtual boost::shared_ptr<IOProcessorImpl> create(InterpreterImpl* interpreter); + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("mmi.event"); + return names; + } + virtual Data getDataModelVariables(); + virtual void send(const SendRequest& req); + protected: + MMISessionManager* _sessionManager; + }; + + void send(const std::string& name, const SendRequest& req); + + /// HTTPServlet + void httpRecvRequest(const HTTPServer::Request& req); + void setURL(const std::string& url) { + _url = url; + } + std::string getURL() { return _url; } + + bool canAdaptPath() { + return false; + } + + protected: + void received(const NewContextRequest& mmiEvent, const std::string& token = ""); + void received(const NewContextResponse& mmiEvent); + void received(const ExtensionNotification& mmiEvent); + + void setupHTMLClient(const HTTPServer::Request& req); + + Interpreter _protoInterpreter; + Factory* _factory; + DelayedEventQueue _eventQueue; + std::map<std::string, MMISession*> _sessions; + std::map<std::string, MMISession*> _tokens; + std::string _url; + }; +} + + +#endif /* end of include guard: MMISESSIONMANAGER_H_IHDWUAKD */ diff --git a/apps/w3c-mmi/im/uscxml-interaction-manager.cpp b/apps/w3c-mmi/im/uscxml-interaction-manager.cpp new file mode 100644 index 0000000..a7162cc --- /dev/null +++ b/apps/w3c-mmi/im/uscxml-interaction-manager.cpp @@ -0,0 +1,182 @@ +#include "uscxml/config.h" +#include "uscxml/Interpreter.h" +#include <glog/logging.h> +#include "uscxml/concurrency/tinythread.h" + +#include "MMISessionManager.h" + +#ifdef HAS_SIGNAL_H +#include <signal.h> +#endif + +#ifdef HAS_EXECINFO_H +#include <execinfo.h> +#endif + +#ifdef HAS_DLFCN_H +#include <dlfcn.h> +#endif + +#ifdef _WIN32 +#include "XGetopt.h" +#endif + +class VerboseMonitor : public uscxml::InterpreterMonitor { + void onStableConfiguration(uscxml::Interpreter interpreter) { + printConfig(interpreter.getConfiguration()); + } + + void beforeCompletion(uscxml::Interpreter interpreter) { + printConfig(interpreter.getConfiguration()); + } + + void printConfig(const Arabica::XPath::NodeSet<std::string>& config) { + std::string seperator; + std::cout << "Config: {"; + for (int i = 0; i < config.size(); i++) { + std::cout << seperator << ATTR(config[i], "id"); + seperator = ", "; + } + std::cout << "}" << std::endl; + } +}; + + +#ifdef HAS_EXECINFO_H +void printBacktrace(void** array, int size) { + char** messages = backtrace_symbols(array, size); + for (int i = 0; i < size && messages != NULL; ++i) { + std::cerr << "\t" << messages[i] << std::endl; + } + std::cerr << std::endl; + free(messages); +} + +#ifdef HAS_DLFCN_H +// see https://gist.github.com/nkuln/2020860 +typedef void (*cxa_throw_type)(void *, void *, void (*) (void *)); +cxa_throw_type orig_cxa_throw = 0; + +void load_orig_throw_code() { + orig_cxa_throw = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw"); +} + +extern "C" +void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) { + std::cerr << __FUNCTION__ << " will throw exception from " << std::endl; + if (orig_cxa_throw == 0) + load_orig_throw_code(); + + void *array[50]; + size_t size = backtrace(array, 50); + printBacktrace(array, size); + orig_cxa_throw(thrown_exception, pvtinfo, dest); +} +#endif +#endif + + +// see http://stackoverflow.com/questions/2443135/how-do-i-find-where-an-exception-was-thrown-in-c +void customTerminate() { + static bool tried_throw = false; + try { + // try once to re-throw currently active exception + if (!tried_throw) { + throw; + tried_throw = true; + } else { + tried_throw = false; + }; + } catch (const std::exception &e) { + std::cerr << __FUNCTION__ << " caught unhandled exception. what(): " + << e.what() << std::endl; + } catch (const uscxml::Event &e) { + std::cerr << __FUNCTION__ << " caught unhandled exception. Event: " + << e << std::endl; + } catch (...) { + std::cerr << __FUNCTION__ << " caught unknown/unhandled exception." + << std::endl; + } + +#ifdef HAS_EXECINFO_H + void * array[50]; + int size = backtrace(array, 50); + + printBacktrace(array, size); +#endif + abort(); +} + +void printUsageAndExit() { + printf("uscxml-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n"); + printf("Usage\n"); + printf("\tuscxml-browser"); +#ifdef BUILD_AS_PLUGINS + printf(" [-d pluginPath]"); +#endif + printf(" URL\n"); + printf("\n"); + printf("Options\n"); + printf("\t-v : be verbose\n"); + printf("\t-pN : port for HTTP server\n"); + printf("\n"); + exit(1); +} + +int main(int argc, char** argv) { + using namespace uscxml; + + std::set_terminate(customTerminate); + +#if defined(HAS_SIGNAL_H) && !defined(WIN32) + signal(SIGPIPE, SIG_IGN); +#endif + + if (argc < 2) { + printUsageAndExit(); + } + + bool verbose = false; + size_t port = 8080; + google::InitGoogleLogging(argv[0]); + google::LogToStderr(); + +#ifndef _WIN32 + opterr = 0; +#endif + int option; + while ((option = getopt(argc, argv, "vl:d:p:")) != -1) { + switch(option) { + case 'l': + google::InitGoogleLogging(optarg); + break; + case 'd': + uscxml::Factory::pluginPath = optarg; + break; + case 'p': + port = strTo<size_t>(optarg); + break; + case 'v': + verbose = true; + break; + case '?': + break; + default: + printUsageAndExit(); + break; + } + } + + // intialize http server on given port + HTTPServer::getInstance(port); + + LOG(INFO) << "Processing " << argv[optind]; + Interpreter protoInterpreter = Interpreter::fromURI(argv[optind]); + if (protoInterpreter) { + MMISessionManager mmiSessionManager(protoInterpreter); + while(true) + tthread::this_thread::sleep_for(tthread::chrono::milliseconds(1000)); + } + + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/apps/w3c-mmi/mc/uscxml-modality-component.cpp b/apps/w3c-mmi/mc/uscxml-modality-component.cpp new file mode 100644 index 0000000..afe4e7f --- /dev/null +++ b/apps/w3c-mmi/mc/uscxml-modality-component.cpp @@ -0,0 +1,191 @@ +#include "uscxml/config.h" +#include "uscxml/Interpreter.h" +#include <glog/logging.h> + +#ifdef HAS_SIGNAL_H +#include <signal.h> +#endif + +#ifdef HAS_EXECINFO_H +#include <execinfo.h> +#endif + +#ifdef HAS_DLFCN_H +#include <dlfcn.h> +#endif + +#ifdef _WIN32 +#include "XGetopt.h" +#endif + +class VerboseMonitor : public uscxml::InterpreterMonitor { + void onStableConfiguration(uscxml::Interpreter interpreter) { + printConfig(interpreter.getConfiguration()); + } + + void beforeCompletion(uscxml::Interpreter interpreter) { + printConfig(interpreter.getConfiguration()); + } + + void printConfig(const Arabica::XPath::NodeSet<std::string>& config) { + std::string seperator; + std::cout << "Config: {"; + for (int i = 0; i < config.size(); i++) { + std::cout << seperator << ATTR(config[i], "id"); + seperator = ", "; + } + std::cout << "}" << std::endl; + } +}; + + +#ifdef HAS_EXECINFO_H +void printBacktrace(void** array, int size) { + char** messages = backtrace_symbols(array, size); + for (int i = 0; i < size && messages != NULL; ++i) { + std::cerr << "\t" << messages[i] << std::endl; + } + std::cerr << std::endl; + free(messages); +} + +#ifdef HAS_DLFCN_H +// see https://gist.github.com/nkuln/2020860 +typedef void (*cxa_throw_type)(void *, void *, void (*) (void *)); +cxa_throw_type orig_cxa_throw = 0; + +void load_orig_throw_code() { + orig_cxa_throw = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw"); +} + +extern "C" +void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) { + std::cerr << __FUNCTION__ << " will throw exception from " << std::endl; + if (orig_cxa_throw == 0) + load_orig_throw_code(); + + void *array[50]; + size_t size = backtrace(array, 50); + printBacktrace(array, size); + orig_cxa_throw(thrown_exception, pvtinfo, dest); +} +#endif +#endif + + +// see http://stackoverflow.com/questions/2443135/how-do-i-find-where-an-exception-was-thrown-in-c +void customTerminate() { + static bool tried_throw = false; + try { + // try once to re-throw currently active exception + if (!tried_throw) { + throw; + tried_throw = true; + } else { + tried_throw = false; + }; + } catch (const std::exception &e) { + std::cerr << __FUNCTION__ << " caught unhandled exception. what(): " + << e.what() << std::endl; + } catch (const uscxml::Event &e) { + std::cerr << __FUNCTION__ << " caught unhandled exception. Event: " + << e << std::endl; + } catch (...) { + std::cerr << __FUNCTION__ << " caught unknown/unhandled exception." + << std::endl; + } + +#ifdef HAS_EXECINFO_H + void * array[50]; + int size = backtrace(array, 50); + + printBacktrace(array, size); +#endif + abort(); +} + +void printUsageAndExit() { + printf("uscxml-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n"); + printf("Usage\n"); + printf("\tuscxml-browser"); +#ifdef BUILD_AS_PLUGINS + printf(" [-d pluginPath]"); +#endif + printf(" URL\n"); + printf("\n"); + printf("Options\n"); + printf("\t-v : be verbose\n"); + printf("\t-pN : port for HTTP server\n"); + printf("\n"); + exit(1); +} + +int main(int argc, char** argv) { + using namespace uscxml; + + std::set_terminate(customTerminate); + +#if defined(HAS_SIGNAL_H) && !defined(WIN32) + signal(SIGPIPE, SIG_IGN); +#endif + + if (argc < 2) { + printUsageAndExit(); + } + + bool verbose = false; + size_t port = 8080; + google::InitGoogleLogging(argv[0]); + google::LogToStderr(); + +#ifndef _WIN32 + opterr = 0; +#endif + int option; + while ((option = getopt(argc, argv, "vl:d:p:")) != -1) { + switch(option) { + case 'l': + google::InitGoogleLogging(optarg); + break; + case 'd': + uscxml::Factory::pluginPath = optarg; + break; + case 'p': + port = strTo<size_t>(optarg); + break; + case 'v': + verbose = true; + break; + case '?': + break; + default: + printUsageAndExit(); + break; + } + } + +// for (int i = 0; i < argc; i++) +// std::cout << argv[i] << std::endl; +// std::cout << optind << std::endl; + + // intialize http server on given port + HTTPServer::getInstance(port); + + LOG(INFO) << "Processing " << argv[optind]; + Interpreter interpreter = Interpreter::fromURI(argv[optind]); + if (interpreter) { + interpreter.setCmdLineOptions(argc, argv); +// interpreter->setCapabilities(Interpreter::CAN_NOTHING); +// interpreter->setCapabilities(Interpreter::CAN_BASIC_HTTP | Interpreter::CAN_GENERIC_HTTP); + + if (verbose) { + VerboseMonitor* vm = new VerboseMonitor(); + interpreter.addMonitor(vm); + } + + interpreter.start(); + while(interpreter.runOnMainThread(25)); + } + + return EXIT_SUCCESS; +}
\ No newline at end of file |