diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-06-20 19:53:21 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-06-20 19:53:21 (GMT) |
commit | 794575f01ce5a6bf7e377eb815f3def5aded74f5 (patch) | |
tree | 9c59df64ee290f68b7b6c8698bfac4169684485e /src/uscxml/plugins/invoker/xhtml | |
parent | d304f85417e3175c5f2ca159dd303309c24e7b81 (diff) | |
download | uscxml-794575f01ce5a6bf7e377eb815f3def5aded74f5.zip uscxml-794575f01ce5a6bf7e377eb815f3def5aded74f5.tar.gz uscxml-794575f01ce5a6bf7e377eb815f3def5aded74f5.tar.bz2 |
New version with XHTML invoker
Diffstat (limited to 'src/uscxml/plugins/invoker/xhtml')
-rw-r--r-- | src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp | 195 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.h | 55 |
2 files changed, 250 insertions, 0 deletions
diff --git a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp new file mode 100644 index 0000000..0c7ef08 --- /dev/null +++ b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp @@ -0,0 +1,195 @@ +#include <uscxml/config.h> +#include "XHTMLInvoker.h" +#include <glog/logging.h> +#include <uscxml/plugins/ioprocessor/comet/CometIOProcessor.h> + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +#if defined(__APPLE__) and defined(TARGET_OS_MAC) +#include <CoreFoundation/CFBundle.h> +#include <ApplicationServices/ApplicationServices.h> +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new XHTMLInvokerProvider() ); + return true; +} +#endif + +XHTMLInvoker::XHTMLInvoker() { +} + +XHTMLInvoker::~XHTMLInvoker() { +}; + +boost::shared_ptr<InvokerImpl> XHTMLInvoker::create(InterpreterImpl* interpreter) { + boost::shared_ptr<XHTMLInvoker> invoker = boost::shared_ptr<XHTMLInvoker>(new XHTMLInvoker()); + invoker->_interpreter = interpreter; +// _ioProc = interpreter->getFactory()->createIOProcessor("comet", interpreter); + return invoker; +} + +bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { + tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); + + // these are the XHR requests + if (boost::iequals(req.data["header"]["X-Requested-With"].atom, "XMLHttpRequest")) { + if (boost::iequals(req.data["type"].atom, "get")) { + if (_longPoll) { + evhttp_send_error(_longPoll.curlReq, 204, NULL); + _longPoll.curlReq = NULL; + } + _longPoll = req; + if (!_outQueue.empty()) { + send(_outQueue.front()); + _outQueue.pop_front(); + } + return true; + } else { + Event ev(req); + if (ev.data["header"]["X-SCXML-Name"]) { + ev.name = ev.data["header"]["X-SCXML-Name"].atom; + } + ev.origin = _invokeId; + ev.initContent(req.data["content"].atom); + ev.data.compound["Connection"] = req.data; + // content is already on ev.raw + ev.data.compound["Connection"].compound.erase("content"); + + returnEvent(ev); + return true; + } + } + + // initial request for a document + if (!req.data["query"] && // no query parameters + boost::iequals(req.data["type"].atom, "get") && // request type is GET + (boost::icontains(req.data["header"]["Accept"].atom, "text/html") || // accepts html or + boost::contains(req.data["header"]["User-Agent"].atom, "MSIE")) && // is the internet explorer + req.content.length() == 0) { // no content + + HTTPServer::Reply reply(req); + URL templateURL("templates/xhtml-invoker.html"); + templateURL.toAbsolute(_interpreter->getBaseURI()); + templateURL.download(true); + std::string templateContent = templateURL.getInContent(); + boost::replace_all(templateContent, "${scxml.server}", _url); + boost::replace_all(templateContent, "${scxml.invokeId}", _invokeId); + + std::string content; + std::stringstream ss; + if (_invokeReq.dom) { + ss << _invokeReq.getFirstDOMElement(); + content = ss.str(); + } else if(_invokeReq.data) { + ss << _invokeReq.data; + content = ss.str(); + } else { + content = _invokeReq.content; + } + boost::replace_all(templateContent, "${scxml.content}", content); + reply.content = templateContent; + reply.headers["Content-Type"] = "text/html"; + + // aggressive caching in IE will return all XHR get requests instantenously with the template otherwise + reply.headers["Cache-Control"] = "no-cache"; + + HTTPServer::reply(reply); + + // queue invoke request for initial html + _longPoll.curlReq = NULL; + _outQueue = std::deque<SendRequest>(); + SendRequest sendReq(_invokeReq); + send(sendReq); + + return true; + } + + // don't know what to do with other requests + return false; +} + +Data XHTMLInvoker::getDataModelVariables() { + Data data; + return data; +} + +void XHTMLInvoker::send(const SendRequest& req) { + tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); + if (!_longPoll) { + _outQueue.push_back(req); + return; + } + reply(req, _longPoll); + _longPoll.curlReq = NULL; +} + +void XHTMLInvoker::reply(const SendRequest& req, const HTTPServer::Request& longPoll) { + HTTPServer::Reply reply(longPoll); + + if (req.dom) { + std::stringstream ss; + Arabica::DOM::Node<std::string> content = req.dom.getDocumentElement(); + if (content && boost::iequals(content.getLocalName(), "content")) { + reply.headers["X-SCXML-Type"] = (HAS_ATTR(content, "type") ? ATTR(content, "type") : "replacechildren"); + reply.headers["X-SCXML-XPath"] = (HAS_ATTR(content, "xpath") ? ATTR(content, "xpath") : "/html/body"); + if (HAS_ATTR(content, "attr")) + reply.headers["X-SCXML-Attr"] = ATTR(content, "attr"); + } + ss << req.getFirstDOMElement(); + reply.content = ss.str(); + reply.headers["Content-Type"] = "application/xml"; + } else if (req.data) { + reply.content = Data::toJSON(req.data); + reply.headers["Content-Type"] = "application/json"; + } else if (req.content.length() > 0) { + reply.content = req.content; + reply.headers["Content-Type"] = "application/text"; + } + + if (req.params.find("Content-Type") != req.params.end()) + reply.headers["Content-Type"] = req.params.find("Content-Type")->first; + + HTTPServer::reply(reply); +} + +void XHTMLInvoker::cancel(const std::string sendId) { +} + +void XHTMLInvoker::invoke(const InvokeRequest& req) { + _invokeReq = req; + HTTPServer::registerServlet(_interpreter->getName() + "/xhtml/" + req.invokeid, this); +#if defined(__APPLE__) and defined(TARGET_OS_MAC) + // see http://stackoverflow.com/questions/4177744/c-osx-open-default-browser + CFURLRef url = CFURLCreateWithBytes ( + NULL, // allocator + (UInt8*)_url.c_str(), // URLBytes + _url.length(), // length + kCFStringEncodingASCII, // encoding + NULL // baseURL + ); + LSOpenCFURLRef(url,0); + CFRelease(url); + return; +#endif +#ifdef _WIN32 +// see http://support.microsoft.com/kb/224816 + ShellExecute(NULL, "open", _url.c_str(), NULL, NULL, SW_SHOWNORMAL); + return; +#endif +#ifdef HAS_XDG_OPEN + std::string systemCmd; + systemCmd = "xdg-open "; + systemCmd += _url; + system(systemCmd.c_str()); + return; +#endif +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.h b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.h new file mode 100644 index 0000000..e94c4fd --- /dev/null +++ b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.h @@ -0,0 +1,55 @@ +#ifndef XHTMLINVOKER_H_W09J90F0 +#define XHTMLINVOKER_H_W09J90F0 + +#include <uscxml/Interpreter.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class XHTMLInvoker : public InvokerImpl, public HTTPServlet { +public: + XHTMLInvoker(); + virtual ~XHTMLInvoker(); + virtual boost::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("xhtml"); + names.insert("http://www.w3.org/1999/xhtml"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void send(const SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(const InvokeRequest& req); + + // HTTPServlet + virtual bool httpRecvRequest(const HTTPServer::Request& request); + virtual void setURL(const std::string& url) { + _url = url; + } + + void reply(const SendRequest& req, const HTTPServer::Request& longPoll); + +protected: + HTTPServer::Request _longPoll; + std::deque<SendRequest> _outQueue; + + tthread::recursive_mutex _mutex; + InvokeRequest _invokeReq; + IOProcessor _ioProc; + std::string _url; +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(XHTMLInvoker, InvokerImpl); +#endif + +} + + +#endif /* end of include guard: XHTMLINVOKER_H_W09J90F0 */ |