summaryrefslogtreecommitdiffstats
path: root/apps/w3c-mmi
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-06-10 22:47:14 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-06-10 22:47:14 (GMT)
commit6f56474450b7c54f2c95b5dea6a7a42623141649 (patch)
tree420c52085d8cf778360c09baf9722b21d01259da /apps/w3c-mmi
parenta154682fc1b25581742d38dd5fe9aa06ede167b7 (diff)
downloaduscxml-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.cpp210
-rw-r--r--apps/w3c-mmi/MMIEventServlet.h59
-rw-r--r--apps/w3c-mmi/im/MMISessionManager.cpp257
-rw-r--r--apps/w3c-mmi/im/MMISessionManager.h81
-rw-r--r--apps/w3c-mmi/im/uscxml-interaction-manager.cpp182
-rw-r--r--apps/w3c-mmi/mc/uscxml-modality-component.cpp191
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