diff options
28 files changed, 1010 insertions, 78 deletions
@@ -14,3 +14,5 @@ package/darwin* package/windows* *.tgz + +*.class diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fa22f8..4c27508 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,10 +287,13 @@ if (APPLE) endif() if (IOS) - set(CMAKE_OSX_DEPLOYMENT_TARGET 4.3) - foreach(FLAGS CMAKE_C_FLAGS CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS) - set(${FLAGS} "${${FLAGS}} -miphoneos-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") - endforeach() + if (${CMAKE_GENERATOR} STREQUAL "Xcode") + else() + set(CMAKE_OSX_DEPLOYMENT_TARGET 4.3) + foreach(FLAGS CMAKE_C_FLAGS CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS) + set(${FLAGS} "${${FLAGS}} -miphoneos-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") + endforeach() + endif() endif() ############################################################ @@ -636,6 +639,10 @@ if (NOT WIN32) add_subdirectory(src/bindings) endif() +#if (IOS) + add_subdirectory(apps/ios) +#endif() + ############################################################ # Header Files ############################################################ diff --git a/apps/w3c-mmi/MMIEventServlet.cpp b/apps/w3c-mmi/MMIEventServlet.cpp index cb5136a..22b8d91 100644 --- a/apps/w3c-mmi/MMIEventServlet.cpp +++ b/apps/w3c-mmi/MMIEventServlet.cpp @@ -68,7 +68,7 @@ bool MMIEventServlet::httpRecvRequest(const HTTPServer::Request& req) { return true; } - std::cout << mmiDoc.getNamespaceURI() << std::endl; +// std::cout << mmiDoc.getNamespaceURI() << std::endl; Node<std::string> mmiEvent = mmiDoc.getFirstChild(); // get the first element while (mmiEvent && mmiEvent.getNodeType() != Node_base::ELEMENT_NODE) { @@ -81,7 +81,7 @@ bool MMIEventServlet::httpRecvRequest(const HTTPServer::Request& req) { mmiEvent = mmiEvent.getNextSibling(); } } - std::cout << mmiEvent << std::endl; +// std::cout << mmiEvent << std::endl; if (!mmiEvent) { evhttp_send_error(req.curlReq, 402, NULL); diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index b3ad09e..7ac3b98 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -392,6 +392,62 @@ boost::shared_ptr<ExecutableContentImpl> Factory::createExecutableContent(const } +size_t DataModelImpl::replaceExpressions(std::string& content) { + std::stringstream ss; + size_t replacements = 0; + size_t indent = 0; + size_t pos = 0; + size_t start = std::string::npos; + size_t end = 0; + while (true) { + // find any of ${} + pos = content.find_first_of("${}", pos); + if (pos == std::string::npos) { + ss << content.substr(end, content.length() - end); + break; + } + if (content[pos] == '$') { + if (content.size() > pos && content[pos+1] == '{') { + pos++; + start = pos + 1; + // copy everything in between + ss << content.substr(end, (start - 2) - end); + } + } else if (content[pos] == '{' && start != std::string::npos) { + indent++; + } else if (content[pos] == '}' && start != std::string::npos) { + if (!indent) { + end = pos; + // we found a token to substitute + std::string expr = content.substr(start, end - start); + end++; + try { + Data data = getStringAsData(expr); +// if (data.type == Data::VERBATIM) { +// ss << "\"" << data.atom << "\""; +// } else { +// ss << data.atom; +// } + ss << Data::toJSON(data); + replacements++; + } catch (Event e) { + // insert unsubstituted + start -= 2; + ss << content.substr(start, end - start); + } + start = std::string::npos; + } else { + indent--; + } + } + pos++; + } + if (replacements) + content = ss.str(); + + return replacements; +} + Factory* Factory::getInstance() { if (_instance == NULL) { diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index 7b08982..2a0ec43 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -10,12 +10,14 @@ #include <string> #include <set> #include <boost/shared_ptr.hpp> +#include <limits> namespace uscxml { // see http://stackoverflow.com/questions/228005/alternative-to-itoa-for-converting-integer-to-string-c template <typename T> std::string toStr(T tmp) { std::ostringstream out; + out.precision(std::numeric_limits<double>::digits10 + 1); out << tmp; return out.str(); } @@ -28,9 +30,9 @@ template <typename T> T strTo(std::string tmp) { } inline bool isNumeric( const char* pszInput, int nNumberBase) { - std::string base = "0123456789ABCDEF"; + std::string base = ".0123456789ABCDEF"; std::string input = pszInput; - return (input.find_first_not_of(base.substr(0, nNumberBase)) == std::string::npos); + return (input.find_first_not_of(base.substr(0, nNumberBase + 1)) == std::string::npos); } class InterpreterImpl; @@ -252,6 +254,8 @@ public: virtual void setEvent(const Event& event) = 0; virtual Data getStringAsData(const std::string& content) = 0; + size_t replaceExpressions(std::string& content); + // foreach virtual uint32_t getLength(const std::string& expr) = 0; virtual void setForeach(const std::string& item, @@ -363,6 +367,10 @@ public: return _impl->isDeclared(expr); } + size_t replaceExpressions(std::string& content) { + return _impl->replaceExpressions(content); + } + protected: boost::shared_ptr<DataModelImpl> _impl; }; diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 158ea96..8c1b4a6 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -436,7 +436,7 @@ void InterpreterImpl::processContentElement(const Arabica::DOM::Node<std::string std::string& expr) { if (HAS_ATTR(content, "expr")) { expr = ATTR(content, "expr"); - } else if (content.hasChildNodes()) { + } else if (content.hasChildNodes() || HAS_ATTR(content, "src") || HAS_ATTR(content, "srcexpr")) { processDOMorText(content, dom, text); } else { LOG(ERROR) << "content element does not specify any content."; @@ -455,7 +455,7 @@ void InterpreterImpl::processDOMorText(const Arabica::DOM::Node<std::string>& no LOG(ERROR) << LOCALNAME(node) << " element has relative src or srcexpr URI with no baseURI set."; return; } - if (_cachedURLs.find(sourceURL.asString()) != _cachedURLs.end()) { + if (_cachedURLs.find(sourceURL.asString()) != _cachedURLs.end() && false) { srcContent << _cachedURLs[sourceURL.asString()]; } else { srcContent << sourceURL; @@ -473,8 +473,12 @@ void InterpreterImpl::processDOMorText(const Arabica::DOM::Node<std::string>& no std::auto_ptr<std::istream> ssPtr(ss); Arabica::SAX::InputSource<std::string> inputSource; inputSource.setByteStream(ssPtr); + +// parser.setFeature(Arabica::SAX::FeatureNames<std::string>().external_general, true); + if (parser.parse(inputSource) && parser.getDocument()) { dom = parser.getDocument(); + std::cout << dom; Node<std::string> content = dom.getDocumentElement(); assert(content.getNodeType() == Node_base::ELEMENT_NODE); Node<std::string> container = dom.createElement("container"); @@ -1106,7 +1110,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node<std::string>& cont } std::stringstream srcContent; - if (_cachedURLs.find(scriptUrl.asString()) != _cachedURLs.end()) { + if (_cachedURLs.find(scriptUrl.asString()) != _cachedURLs.end() && false) { srcContent << _cachedURLs[scriptUrl.asString()]; } else { srcContent << scriptUrl; @@ -1313,7 +1317,7 @@ Arabica::XPath::NodeSet<std::string> InterpreterImpl::getStates(const std::vecto Arabica::DOM::Node<std::string> InterpreterImpl::getState(const std::string& stateId) { - if (_cachedStates.find(stateId) != _cachedStates.end()) { + if (_cachedStates.find(stateId) != _cachedStates.end() && false) { return _cachedStates[stateId]; } diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index dd62702..dda2279 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -26,7 +26,7 @@ public: INTERPRETED }; - Data() {} + Data() : type(INTERPRETED) {} Data(const std::string& atom_, Type type_ = INTERPRETED) : atom(atom_), type(type_) {} explicit Data(const Arabica::DOM::Node<std::string>& dom); virtual ~Data() {} diff --git a/src/uscxml/NameSpacingParser.h b/src/uscxml/NameSpacingParser.h index fddf306..50cc260 100644 --- a/src/uscxml/NameSpacingParser.h +++ b/src/uscxml/NameSpacingParser.h @@ -6,6 +6,13 @@ namespace uscxml { +class ScriptEntityResolver : public Arabica::SAX::EntityResolver<std::string> { + virtual InputSourceT resolveEntity(const std::string& publicId, const std::string& systemId) { + Arabica::SAX::InputSource<std::string> is; + return is; + } +}; + class NameSpacingParser : public Arabica::SAX2DOM::Parser<std::string> { public: NameSpacingParser(); diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp index 8feb73a..47ec21d 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp @@ -24,10 +24,37 @@ bool connect(pluma::Host& host) { JSCDataModel::JSCDataModel() { } +#if 0 +typedef struct { + int version; /* current (and only) version is 0 */ + JSClassAttributes attributes; + + const char* className; + JSClassRef parentClass; + + const JSStaticValue* staticValues; + const JSStaticFunction* staticFunctions; + + JSObjectInitializeCallback initialize; + JSObjectFinalizeCallback finalize; + JSObjectHasPropertyCallback hasProperty; + JSObjectGetPropertyCallback getProperty; + JSObjectSetPropertyCallback setProperty; + JSObjectDeletePropertyCallback deleteProperty; + JSObjectGetPropertyNamesCallback getPropertyNames; + JSObjectCallAsFunctionCallback callAsFunction; + JSObjectCallAsConstructorCallback callAsConstructor; + JSObjectHasInstanceCallback hasInstance; + JSObjectConvertToTypeCallback convertToType; +} JSClassDefinition; +#endif + // functions need to be objects to hold private data in JSC JSClassDefinition JSCDataModel::jsInClassDef = { 0, 0, "In", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, jsIn, 0, 0, 0 }; JSClassDefinition JSCDataModel::jsPrintClassDef = { 0, 0, "print", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, jsPrint, 0, 0, 0 }; +JSClassDefinition JSCDataModel::jsIOProcessorsClassDef = { 0, 0, "ioProcessors", 0, 0, 0, 0, 0, jsIOProcessorHasProp, jsIOProcessorGetProp, 0, 0, jsIOProcessorListProps, 0, 0, 0, 0 }; + boost::shared_ptr<DataModelImpl> JSCDataModel::create(InterpreterImpl* interpreter) { boost::shared_ptr<JSCDataModel> dm = boost::shared_ptr<JSCDataModel>(new JSCDataModel()); @@ -51,15 +78,33 @@ boost::shared_ptr<DataModelImpl> JSCDataModel::create(InterpreterImpl* interpret JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), printName, jsPrint, kJSPropertyAttributeNone, NULL); JSStringRelease(inName); - dm->eval("_ioprocessors = {};"); + JSClassRef jsIOProcClassRef = JSClassCreate(&jsIOProcessorsClassDef); + JSObjectRef jsIOProc = JSObjectMake(dm->_ctx, jsIOProcClassRef, dm.get()); + JSStringRef ioProcName = JSStringCreateWithUTF8CString("_ioprocessors"); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), ioProcName, jsIOProc, kJSPropertyAttributeNone, NULL); + JSStringRelease(ioProcName); + + JSStringRef nameName = JSStringCreateWithUTF8CString("_name"); + JSStringRef name = JSStringCreateWithUTF8CString(dm->_interpreter->getName().c_str()); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), nameName, JSValueMakeString(dm->_ctx, name), kJSPropertyAttributeNone, NULL); + JSStringRelease(nameName); + JSStringRelease(name); + + JSStringRef sessionIdName = JSStringCreateWithUTF8CString("_sessionid"); + JSStringRef sessionId = JSStringCreateWithUTF8CString(dm->_interpreter->getSessionId().c_str()); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), sessionIdName, JSValueMakeString(dm->_ctx, sessionId), kJSPropertyAttributeNone, NULL); + JSStringRelease(sessionIdName); + JSStringRelease(sessionId); Arabica::DOM::JSCDocument::JSCDocumentPrivate* privData = new Arabica::DOM::JSCDocument::JSCDocumentPrivate(); - privData->nativeObj = new Arabica::DOM::Document<std::string>(interpreter->getDocument()); - privData->dom = dm->_dom; + if (interpreter) { + privData->nativeObj = new Arabica::DOM::Document<std::string>(interpreter->getDocument()); + privData->dom = dm->_dom; - JSObjectRef documentObject = JSObjectMake(dm->_ctx, Arabica::DOM::JSCDocument::getTmpl(), privData); - JSObjectRef globalObject = JSContextGetGlobalObject(dm->_ctx); - JSObjectSetProperty(dm->_ctx, globalObject, JSStringCreateWithUTF8CString("document"), documentObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, NULL); + JSObjectRef documentObject = JSObjectMake(dm->_ctx, Arabica::DOM::JSCDocument::getTmpl(), privData); + JSObjectRef globalObject = JSContextGetGlobalObject(dm->_ctx); + JSObjectSetProperty(dm->_ctx, globalObject, JSStringCreateWithUTF8CString("document"), documentObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, NULL); + } dm->eval("_invokers = {};"); dm->eval("_x = {};"); @@ -202,10 +247,9 @@ Data JSCDataModel::getValueAsData(const JSValueRef value) { JSValueRef exception = NULL; switch(JSValueGetType(_ctx, value)) { case kJSTypeUndefined: - LOG(ERROR) << "IsUndefined is unimplemented"; - break; case kJSTypeNull: - LOG(ERROR) << "IsNull is unimplemented"; + data.atom = "null"; + data.type = Data::INTERPRETED; break; case kJSTypeBoolean: data.atom = (JSValueToBoolean(_ctx, value) ? "true" : "false"); @@ -225,6 +269,7 @@ Data JSCDataModel::getValueAsData(const JSValueRef value) { JSStringGetUTF8CString(stringValue, buf, maxSize); data.atom = std::string(buf); + data.type = Data::VERBATIM; JSStringRelease(stringValue); free(buf); break; @@ -488,4 +533,43 @@ JSValueRef JSCDataModel::jsIn(JSContextRef ctx, JSObjectRef function, JSObjectRe } +bool JSCDataModel::jsIOProcessorHasProp(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) { + JSCDataModel* INSTANCE = (JSCDataModel*)JSObjectGetPrivate(object); + std::map<std::string, IOProcessor> ioProcessors = INSTANCE->_interpreter->getIOProcessors(); + + size_t maxSize = JSStringGetMaximumUTF8CStringSize(propertyName); + char buffer[maxSize]; + JSStringGetUTF8CString(propertyName, buffer, maxSize); + std::string prop(buffer); + + return ioProcessors.find(prop) != ioProcessors.end(); +} + +JSValueRef JSCDataModel::jsIOProcessorGetProp(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { + JSCDataModel* INSTANCE = (JSCDataModel*)JSObjectGetPrivate(object); + std::map<std::string, IOProcessor> ioProcessors = INSTANCE->_interpreter->getIOProcessors(); + + size_t maxSize = JSStringGetMaximumUTF8CStringSize(propertyName); + char buffer[maxSize]; + JSStringGetUTF8CString(propertyName, buffer, maxSize); + std::string prop(buffer); + + if (ioProcessors.find(prop) != ioProcessors.end()) { + return INSTANCE->getDataAsValue(ioProcessors.find(prop)->second.getDataModelVariables()); + } + return JSValueMakeUndefined(ctx); +} + +void JSCDataModel::jsIOProcessorListProps(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) { + JSCDataModel* INSTANCE = (JSCDataModel*)JSObjectGetPrivate(object); + std::map<std::string, IOProcessor> ioProcessors = INSTANCE->_interpreter->getIOProcessors(); + + std::map<std::string, IOProcessor>::const_iterator ioProcIter = ioProcessors.begin(); + while(ioProcIter != ioProcessors.end()) { + JSStringRef ioProcName = JSStringCreateWithUTF8CString(ioProcIter->first.c_str()); + JSPropertyNameAccumulatorAddName(propertyNames, ioProcName); + ioProcIter++; + } +} + }
\ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h index 28a313e..36765c2 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h @@ -66,6 +66,11 @@ protected: static JSClassDefinition jsPrintClassDef; static JSValueRef jsPrint(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); + static JSClassDefinition jsIOProcessorsClassDef; + static bool jsIOProcessorHasProp(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName); + static JSValueRef jsIOProcessorGetProp(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception); + static void jsIOProcessorListProps(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames); + JSValueRef getDocumentAsValue(const Arabica::DOM::Document<std::string>& doc); JSValueRef getDataAsValue(const Data& data); Data getValueAsData(const JSValueRef value); diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index c92274c..2e37b29 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -264,13 +264,17 @@ void SWIDataModel::eval(const std::string& expr) { } bool SWIDataModel::evalAsBool(const std::string& expr) { - PlCompound compound(expr.c_str()); - PlTermv termv(compound.arity()); - for (int i = 0; i < compound.arity(); i++) { - termv[i] = compound[i + 1]; + try { + PlCompound compound(expr.c_str()); + PlTermv termv(compound.arity()); + for (int i = 0; i < compound.arity(); i++) { + termv[i] = compound[i + 1]; + } + PlQuery query(compound.name(), termv); + return query.next_solution() > 0; + } catch(...) { + return false; } - PlQuery query(compound.name(), termv); - return query.next_solution() > 0; } std::string SWIDataModel::evalAsString(const std::string& expr) { diff --git a/src/uscxml/plugins/invoker/CMakeLists.txt b/src/uscxml/plugins/invoker/CMakeLists.txt index 34d8918..e836275 100644 --- a/src/uscxml/plugins/invoker/CMakeLists.txt +++ b/src/uscxml/plugins/invoker/CMakeLists.txt @@ -32,6 +32,25 @@ else() list (APPEND USCXML_FILES ${DIRMON_INVOKER}) endif() + +# Location invoker to watch for proximity to GPS coordinates + +file(GLOB_RECURSE LOCATION_INVOKER + location/*.cpp + location/*.h +) +source_group("Invoker\\location" FILES ${LOCATION_INVOKER}) +if (BUILD_AS_PLUGINS) + add_library( + invoker_location SHARED + ${LOCATION_INVOKER}) + target_link_libraries(invoker_location uscxml) + set_target_properties(invoker_location PROPERTIES FOLDER "Plugin Invoker") +else() + list (APPEND USCXML_FILES ${LOCATION_INVOKER}) +endif() + + # System invoker to open a native command file(GLOB_RECURSE XHTML_INVOKER diff --git a/src/uscxml/plugins/invoker/location/LocationInvoker.cpp b/src/uscxml/plugins/invoker/location/LocationInvoker.cpp new file mode 100644 index 0000000..9aeb6b4 --- /dev/null +++ b/src/uscxml/plugins/invoker/location/LocationInvoker.cpp @@ -0,0 +1,44 @@ +#include "LocationInvoker.h" +#include <glog/logging.h> + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new LocationInvokerProvider() ); + return true; +} +#endif + +LocationInvoker::LocationInvoker() { +} + +LocationInvoker::~LocationInvoker() { +}; + +boost::shared_ptr<InvokerImpl> LocationInvoker::create(InterpreterImpl* interpreter) { + boost::shared_ptr<LocationInvoker> invoker = boost::shared_ptr<LocationInvoker>(new LocationInvoker()); + invoker->_interpreter = interpreter; + return invoker; +} + +Data LocationInvoker::getDataModelVariables() { + Data data; + return data; +} + +void LocationInvoker::send(const SendRequest& req) { +} + +void LocationInvoker::cancel(const std::string sendId) { +} + +void LocationInvoker::invoke(const InvokeRequest& req) { +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/location/LocationInvoker.h b/src/uscxml/plugins/invoker/location/LocationInvoker.h new file mode 100644 index 0000000..2eb4833 --- /dev/null +++ b/src/uscxml/plugins/invoker/location/LocationInvoker.h @@ -0,0 +1,40 @@ +#ifndef LOCATIONINVOKER_H_W09J90F0 +#define LOCATIONINVOKER_H_W09J90F0 + +#include <uscxml/Interpreter.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class LocationInvoker : public InvokerImpl { +public: + LocationInvoker(); + virtual ~LocationInvoker(); + virtual boost::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("location"); + names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#location"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void send(const SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(const InvokeRequest& req); + +protected: +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(LocationInvoker, InvokerImpl); +#endif + +} + + +#endif /* end of include guard: LOCATIONINVOKER_H_W09J90F0 */ diff --git a/src/uscxml/plugins/invoker/miles/SpatialAudio.cpp b/src/uscxml/plugins/invoker/miles/SpatialAudio.cpp index 3826ebb..298b15f 100644 --- a/src/uscxml/plugins/invoker/miles/SpatialAudio.cpp +++ b/src/uscxml/plugins/invoker/miles/SpatialAudio.cpp @@ -28,11 +28,11 @@ SpatialAudio::SpatialAudio() { _pos[0] = _pos[1] = _pos[2] = 0.0; _listener = new float[3]; _listener[0] = _listener[1] = _listener[2] = 0.0; + _maxPos = new float[3]; + _maxPos[0] = _maxPos[1] = _maxPos[2] = 1.0; miles_init(); - } - SpatialAudio::~SpatialAudio() { }; @@ -53,8 +53,8 @@ void SpatialAudio::send(const SendRequest& req) { _audioDev = miles_audio_device_open(MILES_AUDIO_IO_OPENAL, _audioDevIndex, 0, 22050, 2, 1, 1024, false); if (_audioDev != NULL) { _audioDevOpen = true; - float rolloffFactor = 0.2; - miles_audio_device_control(MILES_AUDIO_IO_OPENAL, _audioDev, MILES_AUDIO_DEVICE_CTRL_SET_ROLLOFF_FACTOR, &rolloffFactor); +// float rolloffFactor = 1.0; +// miles_audio_device_control(MILES_AUDIO_IO_OPENAL, _audioDev, MILES_AUDIO_DEVICE_CTRL_SET_ROLLOFF_FACTOR, &rolloffFactor); } } @@ -70,24 +70,30 @@ void SpatialAudio::send(const SendRequest& req) { miles_audio_device_control(MILES_AUDIO_IO_OPENAL, _audioDev, MILES_AUDIO_DEVICE_CTRL_SET_POSITION, _pos); + char* buffer = (char*)malloc(_audioDev->chunk_size); // skip wav header _dataStream.seekg(44); - + while(_dataStream.readsome(buffer, _audioDev->chunk_size) != 0) { - miles_audio_device_write(MILES_AUDIO_IO_OPENAL, _audioDev, buffer, _audioDev->chunk_size); + int written = 0; + while(written < _audioDev->chunk_size) { + written += miles_audio_device_write(MILES_AUDIO_IO_OPENAL, _audioDev, buffer + written, _audioDev->chunk_size - written); + tthread::this_thread::sleep_for(tthread::chrono::milliseconds(10)); + } } + _dataStream.seekg(0); free(buffer); } } else if (boost::iequals(req.name, "move.listener")) { if (_audioDevOpen) { getPosFromParams(req.params, _listener); - std::cout << "Listener: "; - for (int i = 0; i < 3; i++) { - std::cout << _listener[i] << " "; - } - std::cout << std::endl; +// std::cout << "Listener: "; +// for (int i = 0; i < 3; i++) { +// std::cout << _listener[i] << " "; +// } +// std::cout << std::endl; miles_audio_device_control(MILES_AUDIO_IO_OPENAL, _audioDev, MILES_AUDIO_DEVICE_CTRL_SET_LISTENER_POS, _listener); @@ -119,6 +125,17 @@ void SpatialAudio::invoke(const InvokeRequest& req) { getPosFromParams(req.params, _pos); + std::multimap<std::string, std::string>::const_iterator paramIter = req.params.begin(); + while(paramIter != req.params.end()) { + if (boost::iequals(paramIter->first, "maxX")) + _maxPos[0] = strTo<float>(paramIter->second); + if (boost::iequals(paramIter->first, "maxY")) + _maxPos[1] = strTo<float>(paramIter->second); + if (boost::iequals(paramIter->first, "maxZ")) + _maxPos[2] = strTo<float>(paramIter->second); + paramIter++; + } + struct miles_audio_device_description *devices; int ndevs; @@ -170,6 +187,10 @@ void SpatialAudio::getPosFromParams(const std::multimap<std::string, std::string } catch (boost::bad_lexical_cast& e) { LOG(ERROR) << "Cannot interpret circle as float value in params: " << e.what(); } + + position[0] = position[0] / _maxPos[0]; + position[1] = position[1] / _maxPos[1]; + position[2] = position[2] / _maxPos[2]; // std::cout << _pos[0] << ":" << _pos[1] << ":" << _pos[2] << std::endl; } diff --git a/src/uscxml/plugins/invoker/miles/SpatialAudio.h b/src/uscxml/plugins/invoker/miles/SpatialAudio.h index 082d796..59ecfdb 100644 --- a/src/uscxml/plugins/invoker/miles/SpatialAudio.h +++ b/src/uscxml/plugins/invoker/miles/SpatialAudio.h @@ -45,6 +45,7 @@ protected: float* _pos; float* _listener; + float* _maxPos; bool _audioDevOpen; int _audioDevIndex; struct miles_audio_device* _audioDev; diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp index 2b3377e..081842f 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp @@ -247,7 +247,11 @@ void UmundoInvoker::receive(void* object, umundo::Message* msg) { // get meta fields into event std::map<std::string, std::string>::const_iterator metaIter = msg->getMeta().begin(); while(metaIter != msg->getMeta().end()) { - event.data.compound[metaIter->first] = Data(metaIter->second, Data::VERBATIM); + if (isNumeric(metaIter->second.c_str(), 10)) { + event.data.compound[metaIter->first] = Data(metaIter->second, Data::INTERPRETED); + } else { + event.data.compound[metaIter->first] = Data(metaIter->second, Data::VERBATIM); + } metaIter++; } @@ -309,9 +313,13 @@ std::multimap<std::string, std::pair<std::string, boost::weak_ptr<umundo::Node> boost::shared_ptr<umundo::Node> UmundoInvoker::getNode(InterpreterImpl* interpreter, const std::string& domain) { std::pair<_nodes_t::iterator, _nodes_t::iterator> range = _nodes.equal_range(interpreter->getName()); for (_nodes_t::iterator it = range.first; it != range.second; it++) { - if (it->second.first.compare(domain) == 0) - return it->second.second.lock(); + if (it->second.first.compare(domain) == 0) { + boost::shared_ptr<umundo::Node> node = it->second.second.lock(); + if (node) + return node; + } } + // create a new node boost::shared_ptr<umundo::Node> node = boost::shared_ptr<umundo::Node>(new umundo::Node(domain)); std::pair<std::string, std::pair<std::string, boost::weak_ptr<umundo::Node> > > pair = std::make_pair(interpreter->getName(), std::make_pair(domain, node)); _nodes.insert(pair); diff --git a/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp b/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp index a71d21a..a18be8e 100644 --- a/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp @@ -48,10 +48,20 @@ Data VoiceXMLInvoker::getDataModelVariables() { void VoiceXMLInvoker::send(const SendRequest& req) { StartRequest start; std::stringstream domSS; +// if (req.dom) { +// // hack until jVoiceXML supports XML +// std::cout << req.dom; +// Arabica::DOM::NodeList<std::string> prompts = req.dom.getElementsByTagName("vxml:prompt"); +// for (int i = 0; i < prompts.getLength(); i++) { +// if (prompts.item(i).hasChildNodes()) { +// domSS << prompts.item(i).getFirstChild().getNodeValue() << "."; +// } +// } +// } domSS << req.getFirstDOMElement(); start.content = domSS.str(); - - start.contentURL.href = "http://localhost/~sradomski/hello.vxml"; + _interpreter->getDataModel().replaceExpressions(start.content); + start.requestId = "asdf"; start.source = "asdf"; start.target = "umundo://mmi/jvoicexml"; diff --git a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp index 0c7ef08..4e2c01a 100644 --- a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp @@ -7,9 +7,12 @@ #include <Pluma/Connector.hpp> #endif -#if defined(__APPLE__) and defined(TARGET_OS_MAC) -#include <CoreFoundation/CFBundle.h> -#include <ApplicationServices/ApplicationServices.h> +#if __APPLE__ +# if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +# else +# include <CoreFoundation/CFBundle.h> +# include <ApplicationServices/ApplicationServices.h> +# endif #endif namespace uscxml { @@ -41,6 +44,7 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { // these are the XHR requests if (boost::iequals(req.data["header"]["X-Requested-With"].atom, "XMLHttpRequest")) { if (boost::iequals(req.data["type"].atom, "get")) { + // the long-polling GET if (_longPoll) { evhttp_send_error(_longPoll.curlReq, 204, NULL); _longPoll.curlReq = NULL; @@ -52,9 +56,12 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { } return true; } else { + // a POST request Event ev(req); if (ev.data["header"]["X-SCXML-Name"]) { ev.name = ev.data["header"]["X-SCXML-Name"].atom; + } else { + ev.name = req.data["type"].atom; } ev.origin = _invokeId; ev.initContent(req.data["content"].atom); @@ -62,6 +69,9 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { // content is already on ev.raw ev.data.compound["Connection"].compound.erase("content"); + HTTPServer::Reply reply(req); + HTTPServer::reply(reply); + returnEvent(ev); return true; } @@ -70,17 +80,9 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { // 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; @@ -90,15 +92,25 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { } else if(_invokeReq.data) { ss << _invokeReq.data; content = ss.str(); - } else { + } else if (_invokeReq.content.length() > 0){ content = _invokeReq.content; + } else { + URL templateURL("templates/xhtml-invoker.html"); + templateURL.toAbsolute(_interpreter->getBaseURI()); + templateURL.download(true); + content = templateURL.getInContent(); } - boost::replace_all(templateContent, "${scxml.content}", content); - reply.content = templateContent; - reply.headers["Content-Type"] = "text/html"; + + _interpreter->getDataModel().replaceExpressions(content); + reply.content = content; + + // application/xhtml+xml + reply.headers["Content-Type"] = "text/html; charset=utf-8"; +// reply.headers["Content-Type"] = "application/xhtml+xml; charset=utf-8"; // aggressive caching in IE will return all XHR get requests instantenously with the template otherwise reply.headers["Cache-Control"] = "no-cache"; +// reply.headers["Cache-Control"] = "max-age=3600"; HTTPServer::reply(reply); @@ -122,17 +134,27 @@ Data XHTMLInvoker::getDataModelVariables() { void XHTMLInvoker::send(const SendRequest& req) { tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); + SendRequest reqCopy(req); + _interpreter->getDataModel().replaceExpressions(reqCopy.content); + Data json = Data::fromJSON(reqCopy.content); + if (json) { + reqCopy.data = json; + } + if (!_longPoll) { - _outQueue.push_back(req); + _outQueue.push_back(reqCopy); return; } - reply(req, _longPoll); + reply(reqCopy, _longPoll); _longPoll.curlReq = NULL; } void XHTMLInvoker::reply(const SendRequest& req, const HTTPServer::Request& longPoll) { HTTPServer::Reply reply(longPoll); + // is there JSON in the content? + std::string content = req.content; + if (req.dom) { std::stringstream ss; Arabica::DOM::Node<std::string> content = req.dom.getDocumentElement(); @@ -164,8 +186,10 @@ 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) + HTTPServer::registerServlet(_interpreter->getName() + "/xhtml/" + req.invokeid + ".html", this); +#if __APPLE__ +# if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +# else // see http://stackoverflow.com/questions/4177744/c-osx-open-default-browser CFURLRef url = CFURLCreateWithBytes ( NULL, // allocator @@ -177,6 +201,7 @@ void XHTMLInvoker::invoke(const InvokeRequest& req) { LSOpenCFURLRef(url,0); CFRelease(url); return; +# endif #endif #ifdef _WIN32 // see http://support.microsoft.com/kb/224816 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6e00d52..ba332c2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -40,7 +40,7 @@ if (OFF) set_target_properties(test-dirmon PROPERTIES FOLDER "Tests") endif() -if (OFF) +if (NOT WIN32) add_executable(test-arabica-events src/test-arabica-events.cpp) target_link_libraries(test-arabica-events uscxml) add_test(test-arabica-events ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-arabica-events ${CMAKE_SOURCE_DIR}/test/samples/uscxml/arabica/test-arabica-events.xml) @@ -51,6 +51,11 @@ if (OFF) add_test(test-arabica-xpath ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-arabica-xpath) set_target_properties(test-arabica-xpath PROPERTIES FOLDER "Tests") + add_executable(test-arabica-parsing src/test-arabica-parsing.cpp) + target_link_libraries(test-arabica-parsing uscxml) + add_test(test-arabica-xpath ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-arabica-parsing) + set_target_properties(test-arabica-parsing PROPERTIES FOLDER "Tests") + endif() add_executable(test-url src/test-url.cpp) @@ -58,6 +63,11 @@ target_link_libraries(test-url uscxml) add_test(test-url ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-url) set_target_properties(test-url PROPERTIES FOLDER "Tests") +add_executable(test-datamodel src/test-datamodel.cpp) +target_link_libraries(test-datamodel uscxml) +add_test(test-datamodel ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-datamodel) +set_target_properties(test-datamodel PROPERTIES FOLDER "Tests") + # if (NOT WIN32) # add_executable(test-mmi src/test-mmi.cpp) # target_link_libraries(test-mmi uscxml) diff --git a/test/samples/uscxml/applications/SpatialMapTicker.java b/test/samples/uscxml/applications/SpatialMapTicker.java new file mode 100644 index 0000000..d161264 --- /dev/null +++ b/test/samples/uscxml/applications/SpatialMapTicker.java @@ -0,0 +1,153 @@ +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedList; +import java.util.Random; + +import org.umundo.core.Greeter; +import org.umundo.core.Message; +import org.umundo.core.Node; +import org.umundo.core.Publisher; + +public class SpatialMapTicker { + + Node node; + Publisher pub; + Greeter greeter; + ArrayList<Sensor> sensors = new ArrayList<Sensor>(); + static ArrayList<SensorMessage> messages = new ArrayList<SensorMessage>(); + static Random random = new Random(System.currentTimeMillis()); + + public class SensorMessage { + public String message; + public String severity; + public SensorMessage(String message, String severity) { + this.message = message; + this.severity = severity; + } + public SensorMessage(String message) { + this.message = message; + this.severity = "Notice"; + } + } + + public class Sensor { + @Override + public String toString() { + return "Sensor [id=" + id + ", lat=" + lat + ", lon=" + lon + + ", html=" + getHTML() + "]"; + } + public String id = ""; + public Double lat = new Double(0); + public Double lon = new Double(0); + LinkedList<SensorMessage> messages = new LinkedList<SensorMessage>(); + + public void addMessage(SensorMessage message) { + if (messages.size() > 15) + messages.removeLast(); + messages.addFirst(message); + } + + public String getHTML() { + StringBuilder sb = new StringBuilder(); + for (SensorMessage message : messages) { + sb.append(message.severity); + sb.append(": "); + sb.append(message.message); + sb.append("<br />"); + } + return sb.toString(); + } + } + + public class SensorGreeter extends Greeter { + public void welcome(Publisher publisher, String nodeId, String subId) { + // send all sensors to new subscribers + for (Sensor sensor : sensors) { + Message msg = new Message(); //Message.toSubscriber(subId); + msg.putMeta("id", sensor.id); + msg.putMeta("lat", sensor.lat.toString()); + msg.putMeta("lon", sensor.lon.toString()); + msg.putMeta("html", sensor.getHTML()); + pub.send(msg); + } + } + + @Override + public void farewell(Publisher arg0, String nodeId, String subId) { + } + + } + + public SpatialMapTicker() { + node = new Node(); + pub = new Publisher("map/tick"); + greeter = new SensorGreeter(); + pub.setGreeter(greeter); + node.addPublisher(pub); + + double latCenter = 59.32; + double lonCenter = 18.08; + + int nrSensors = 15; //(int) (Math.random() * 20); + for (int i = 0; i < nrSensors; i++) { + Sensor sensor = new Sensor(); + double latOffset = (Math.random() - 0.5) * 0.3; + double lonOffset = (Math.random() - 0.5) * 0.3; + + sensor.id = "Sensor #" + i; + sensor.lat = latCenter + latOffset; + sensor.lon = lonCenter + lonOffset; + sensors.add(sensor); + } + } + + public static void main(String[] args) { + SpatialMapTicker ticker = new SpatialMapTicker(); + ticker.run(); + } + + private void run() { + messages.add(new SensorMessage("Oil pressure threshold exceeded", "Error")); + messages.add(new SensorMessage("Error #245 in diagnostics unit")); + messages.add(new SensorMessage("Error #32 in diagnostics unit")); + messages.add(new SensorMessage("Error #81 in diagnostics unit")); + messages.add(new SensorMessage("Error #15 in diagnostics unit")); + messages.add(new SensorMessage("Error #145 in diagnostics unit")); + messages.add(new SensorMessage("Unit was moved out of construction site area")); + messages.add(new SensorMessage("Hydraulic pressure exceeding safety limits")); + messages.add(new SensorMessage("Drivers seat belts are not fastened!")); + messages.add(new SensorMessage("Battery recharge cycles exceeded")); + messages.add(new SensorMessage("Unit operated outside recommended paramters")); + + while (true) { + try { + Thread.sleep((long) (Math.random() * 1000) + 200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + Sensor sensor = sensors.get(random.nextInt(sensors.size())); + SensorMessage fault = messages.get(random.nextInt(messages.size())); + + Date now = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss z"); + String nowString = sdf.format(now); + sensor.addMessage(fault); + +// System.out.println("Publishing " + sensor); + + Message msg = new Message(); + msg.putMeta("id", sensor.id); + msg.putMeta("lat", sensor.lat.toString()); + msg.putMeta("lon", sensor.lon.toString()); + msg.putMeta("html", sensor.getHTML()); + msg.putMeta("time", nowString); + msg.putMeta("timeStamp", Long.toString(now.getTime())); + msg.putMeta("lastMsg", sensor.messages.getFirst().message); + msg.putMeta("severity", sensor.messages.getFirst().severity); + pub.send(msg); + } + } + +} diff --git a/test/samples/uscxml/applications/spoken-map-ticker.scxml b/test/samples/uscxml/applications/spoken-map-ticker.scxml new file mode 100644 index 0000000..682429d --- /dev/null +++ b/test/samples/uscxml/applications/spoken-map-ticker.scxml @@ -0,0 +1,64 @@ +<scxml datamodel="ecmascript" name="comet-test" + xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:vxml="http://www.w3.org/2001/vxml" + xmlns="http://www.w3.org/2005/07/scxml"> + + <script src="http://uscxml.tk.informatik.tu-darmstadt.de/scripts/dump.js" /> + + <state id="start"> + <invoke type="xhtml" id="xhtml1"> + <content src="spoken-map-ticker.xhtml" /> + <finalize> + <!-- <script>dump(_event);</script> --> + </finalize> + </invoke> + + <invoke type="vxml" id="vxml" /> + + <invoke type="umundo" id="umundo"> + <param name="channel" expr="'map/tick'" /> + <finalize> + <script>dump(_event);</script> + </finalize> + </invoke> + + <invoke type="http://www.smartvortex.eu/mmi/spatial-audio/" src="../audio/click.wav" id="audio"> + <!-- <param name="maxX" expr="180" /> + <param name="maxY" expr="18" /> + <param name="maxZ" expr="85" /> --> + </invoke> + + <state id="idle"> + <transition target="idle" event="map.center"> + <send event="move.listener" target="#_audio"> + <param name="x" expr="_event.data.lon" /> + <param name="y" expr="18 - _event.data.zoom" /> + <!-- <param name="y" expr="0" /> --> + <param name="z" expr="_event.data.lat" /> + + </send> + </transition> + <transition target="idle" event="umundo.rcvd"> + <send target="#_xhtml1"> + <content>${_event.data}</content> + </send> + <send target="#_audio" event="play" delay="0ms"> + <param name="x" expr="_event.data.lon" /> + <param name="y" expr="0" /> + <param name="z" expr="_event.data.lat" /> + </send> + + <if cond="_event.data.lastMsg"> + <send target="#_vxml"> + <content> + <vxml:prompt> + ${_event.data.lastMsg} + </vxml:prompt> + </content> + </send> + </if> + + </transition> + </state> + </state> +</scxml>
\ No newline at end of file diff --git a/test/samples/uscxml/applications/spoken-map-ticker.xhtml b/test/samples/uscxml/applications/spoken-map-ticker.xhtml new file mode 100644 index 0000000..e656be3 --- /dev/null +++ b/test/samples/uscxml/applications/spoken-map-ticker.xhtml @@ -0,0 +1,236 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <!-- space in between script is required as <script/> is not valid HTML to most browsers --> + <script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.js"> </script> + <script type="text/javascript" src="http://www.openlayers.org/api/OpenLayers.js"> </script> + <script type="text/javascript" src="http://epikur.local/~sradomski/CometSession.js"> </script> + <script type="text/javascript" src="https://raw.github.com/jchavannes/jquery-timer/master/jquery.timer.js"> </script> + + <style type="text/css"> + html, body, #map { + width: 100%; + height: 100%; + margin: 0; + } + .olPopup { + border-radius: 8px; + } + div.olControlOverviewMapElement { + background-color: #666; + } + div.olMap { + width: 180px; + height: 120px; + margin: 0; + } + div.timeRuler { + font-family:Courier,Arial,Helvetica,sans-serif; + font-size: 1.2em; + font-weight: bold; + background-color: #eee; + } + div#message { + overflow: auto; + height: 100%; + font-family:Courier,Arial,Helvetica,sans-serif; + font-size: 0.6em; + } + + div#message p { + padding: 0px; + margin: 4px 2px; + } + + </style> + + <!-- script type="text/javascript" src="http://localhost/~sradomski/CometSession.js"></script --> + <script type="text/javascript"> +//<![CDATA[ + $(document).ready(function() { + var scxml = new CometSession({ + server: document.URL, + onEvent: function(response, message) { + if (message) { + console.log(message); + + if (!markers[message.id]) { + addMarker(message); + } else { + for (i = 0; i < map.popups.length; i++) { + if (map.popups[i].feature.id === message.id) { + map.popups[i].setContentHTML("<h3>" + message.id + "</h3>" + message.html); + } + } + markers[message.id].marker.opacity = 1.0; + markers[message.id].marker.setOpacity(1.0); + + markers[message.id].marker.timer.play(); + markers[message.id].feature.popupContentHTML = "<h3>" + message.id + "</h3>" + message.html; + } + + if (message.lastMsg && message.lastMsg.length > 0) { + var messageDiv = $("#message")[0]; + if (message.timeStamp > lastUpdateTime + 3000) { + var timeRuler = document.createElement("div"); + timeRuler.setAttribute("class", "timeRuler"); + timeRuler.innerHTML = message.time; // + messageDiv.innerHTML; + messageDiv.appendChild(timeRuler); + lastUpdateTime = message.timeStamp; + } + + console.log(message.timeStamp); + console.log(lastUpdateTime); + + var messagePara = document.createElement("p"); + messagePara.innerHTML += message.lastMsg; // + messageDiv.innerHTML; + messageDiv.appendChild(messagePara); + messagePara.addEventListener("mousedown", function() { + var marker = markers[message.id].marker; + marker.events.triggerEvent("mousedown"); + }); + messagePara.addEventListener("mouseover", function() { + messagePara.style.backgroundColor = "#eee"; + }); + messagePara.addEventListener("mouseout", function() { + messagePara.style.backgroundColor = "#fff"; + }); + + if (!stopScrolling) { + messageDiv.scrollTop = messageDiv.scrollHeight; + } + } + } + } + }); + + // var map = new OpenLayers.Map("demoMap"); + // map.addLayer(new OpenLayers.Layer.OSM()); + // map.zoomToMaxExtent(); + + var markers = {}; + var lastUpdateTime = 0; + var stopScrolling = false; + + var fromProjection = new OpenLayers.Projection("EPSG:4326"); // Transform from WGS 1984 + var toProjection = new OpenLayers.Projection("EPSG:900913"); // to Spherical Mercator Projection + + function onMoveEvent() { + var position = map.getCenter().transform(toProjection, fromProjection); + if (Math.random() > 0.7) { // do not publish every move event + scxml.send('map.center', { + 'zoom': map.getZoom(), + 'lon': position.lon, + 'lat': position.lat }); + } + } + + function onMoveEndEvent() { + var position = map.getCenter().transform(toProjection, fromProjection); + scxml.send('map.center', { + 'zoom': map.getZoom(), + 'lon': position.lon, + 'lat': position.lat }); + } + + function addMarker(message) { + var feature = new OpenLayers.Feature( + markerLayer, + new OpenLayers.LonLat(message.lon, message.lat).transform(fromProjection, toProjection)); + feature.closeBox = true; + feature.popupClass = OpenLayers.Class(OpenLayers.Popup.Anchored, { + 'autoSize': true, +// 'maxSize': new OpenLayers.Size(300,200) + }); + feature.data.popupContentHTML = "<h3>" + message.id + "</h3>" + message.html; + feature.data.overflow = "auto"; + feature.data.id = message.id; + var marker = feature.createMarker(); + + marker.timer = $.timer(function() { + if (marker.opacity > 0.5) { + marker.opacity -= 0.02; + marker.setOpacity(marker.opacity); + } else { + marker.timer.stop(); + } + }, 100); + + marker.opacity = 1.0; + marker.setOpacity(marker.opacity); + marker.timer.play(); + + markerClick = function(evt) { + if (this.popup == null) { + this.popup = this.createPopup(this.closeBox); + map.addPopup(this.popup); + this.popup.show(); + } else { + this.popup.toggle(); + } + currentPopup = this.popup; + OpenLayers.Event.stop(evt); + }; + + marker.events.register("mousedown", feature, markerClick); + markers[message.id] = { + 'marker': marker, + 'feature': feature + }; + markerLayer.addMarker(marker); + } + // see also: http://php-baustelle.de/openlayers/step-by-step/ + var map = new OpenLayers.Map('map', { + eventListeners: { + "move": onMoveEvent, + "moveend": onMoveEndEvent, + } + }); + + var mapnik = new OpenLayers.Layer.OSM(); + var markerLayer = new OpenLayers.Layer.Markers("Markers"); +// var attribution = new OpenLayers.Layer.Vector("Attribution", {attribution:"for Smart Vortex"}); + + map.addLayer(mapnik); +// map.addLayer(attribution); + map.addLayer(markerLayer); // has to be the last layer to receive events! + + map.addControl(new OpenLayers.Control.LayerSwitcher()); + // see also http://dev.openlayers.org/releases/OpenLayers-2.12/examples/mousewheel-interval.html + map.addControl(new OpenLayers.Control.Navigation( + {dragPanOptions: {enableKinetic: true}} + )); + + var overview = new OpenLayers.Control.OverviewMap({ + maximized: true, + minRatio: 200, + maxRatio: 300, + }); + map.addControl(overview); + + // stockholm + var position = new OpenLayers.LonLat(18.08,59.32).transform(fromProjection, toProjection); +// var position = new OpenLayers.LonLat(0,0).transform(fromProjection, toProjection); + var zoom = 11; + map.setCenter(position, zoom); + + // var message = { + // 'id': "12", + // 'lat': 59.454441065280534, + // 'lon': 18.062356332194543, + // 'html': '<p>asdf</p>' + // }; + +// addMarker(message); + }); +//]]> + </script> + </head> + <body> + <table width="100%" height="100%"> + <tr> + <td width="20%" height="100%"><div id="message" onmouseover="stopScrolling = true" onmouseout="stopScrolling = false"></div></td> + <td width="80%" height="100%"><div id="map"></div></td> + </tr> + </table> + </body> +</html>
\ No newline at end of file diff --git a/test/samples/uscxml/arabica/test-arabica-parsing.xml b/test/samples/uscxml/arabica/test-arabica-parsing.xml new file mode 100644 index 0000000..f4e46fb --- /dev/null +++ b/test/samples/uscxml/arabica/test-arabica-parsing.xml @@ -0,0 +1,6 @@ +<?xml version="1.0"?> +<root> +<![CDATA[ +< " ' < > & +]]> +</root>
\ No newline at end of file diff --git a/test/samples/uscxml/test-prolog.scxml b/test/samples/uscxml/test-prolog.scxml index 8ccfd6b..def23db 100644 --- a/test/samples/uscxml/test-prolog.scxml +++ b/test/samples/uscxml/test-prolog.scxml @@ -36,7 +36,7 @@ </foreach> </onentry> <transition target="s2" - cond="mother(martha, X), father(bob, X)"/> + cond="mother(martha, X), father(bob, X), in(s1)"/> </state> <state id="s2"> <onentry> @@ -49,21 +49,10 @@ </send> </onentry> <transition - target="idle" + target="end" event="foo" cond="member(element('p',_,_), X), event(data(X))" /> </state> - <state id="idle"> - <transition event="http.post" target="idle"> - <log expr="listing." /> - <respond status="200" to="event(origin(X))" /> - </transition> - <transition event="http.post" cond="" target="idle"> - <log expr="listing." /> - <respond status="200" to="event(origin(X))" /> - </transition> - </state> - <state id="end" final="true" /> </scxml> diff --git a/test/src/test-arabica-parsing.cpp b/test/src/test-arabica-parsing.cpp new file mode 100644 index 0000000..2a09dd6 --- /dev/null +++ b/test/src/test-arabica-parsing.cpp @@ -0,0 +1,48 @@ +#include "uscxml/config.h" +#include "uscxml/Common.h" +#include <DOM/Document.hpp> +#include <XPath/XPath.hpp> +#include <DOM/SAX2DOM/SAX2DOM.hpp> +#include <DOM/io/Stream.hpp> +#include <SAX/helpers/CatchErrorHandler.hpp> +#include <DOM/Events/EventTarget.hpp> +#include <DOM/Events/EventListener.hpp> + +using namespace Arabica::DOM; + +int main(int argc, char** argv) { + + { + std::stringstream* ss = new std::stringstream(); + (*ss) << "<root>\n<![CDATA[\n< \" ' < > &\n]]>\n</root>"; + // we need an auto_ptr for arabica to assume ownership + std::auto_ptr<std::istream> ssPtr(ss); + Arabica::SAX::InputSource<std::string> inputSource(ssPtr); + + Arabica::SAX2DOM::Parser<std::string> domParser; + Arabica::SAX::CatchErrorHandler<std::string> errorHandler; + domParser.setErrorHandler(errorHandler); + + if(!domParser.parse(inputSource)) { + std::cout << errorHandler.errors(); + return -1; + } + std::cout << domParser.getDocument().getDocumentElement().getFirstChild().getNodeValue() << std::endl; + std::cout << domParser.getDocument() << std::endl; + } + { + Arabica::SAX::InputSource<std::string> inputSource; + inputSource.setSystemId("/Users/sradomski/Documents/TK/Code/uscxml/test/samples/uscxml/arabica/test-arabica-parsing.xml"); + + Arabica::SAX2DOM::Parser<std::string> domParser; + Arabica::SAX::CatchErrorHandler<std::string> errorHandler; + domParser.setErrorHandler(errorHandler); + + if(!domParser.parse(inputSource)) { + std::cout << errorHandler.errors(); + return -1; + } + std::cout << domParser.getDocument() << std::endl; + } + +}
\ No newline at end of file diff --git a/test/src/test-datamodel.cpp b/test/src/test-datamodel.cpp new file mode 100644 index 0000000..77f0851 --- /dev/null +++ b/test/src/test-datamodel.cpp @@ -0,0 +1,80 @@ +#include "uscxml/URL.h" +#include "uscxml/Message.h" +#include "uscxml/Interpreter.h" +#include "uscxml/server/HTTPServer.h" + +#include <SAX/helpers/InputSourceResolver.hpp> + +#include <assert.h> +#include <boost/algorithm/string.hpp> +#include <iostream> + +using namespace uscxml; +using namespace boost; + + +int main(int argc, char** argv) { +#ifdef _WIN32 + WSADATA wsaData; + WSAStartup(MAKEWORD(2, 2), &wsaData); +#endif + + DataModel dm(Factory::getInstance()->createDataModel("ecmascript", NULL)); + dm.evalAsString("var foo = 12"); + + { + std::string content = "$"; + int rplc = dm.replaceExpressions(content); + assert(rplc == 0); + std::cout << content << std::endl; + assert(boost::equals(content, "$")); + } + + { + std::string content = "$sadf ${foo}"; + int rplc = dm.replaceExpressions(content); + assert(rplc == 1); + std::cout << content << std::endl; + assert(boost::equals(content, "$sadf 12")); + } + + { + std::string content = "${"; + int rplc = dm.replaceExpressions(content); + assert(rplc == 0); + std::cout << content << std::endl; + assert(boost::equals(content, "${")); + } + + { + std::string content = "${foo}"; + int rplc = dm.replaceExpressions(content); + assert(rplc == 1); + std::cout << content << std::endl; + assert(boost::equals(content, "12")); + } + + { + std::string content = "${bar}"; + int rplc = dm.replaceExpressions(content); + assert(rplc == 0); + std::cout << content << std::endl; + assert(boost::equals(content, "${bar}")); + } + + { + std::string content = "There are ${bar} monkeys! Really ${foo} monkeys!"; + int rplc = dm.replaceExpressions(content); + assert(rplc == 1); + std::cout << content << std::endl; + assert(boost::equals(content, "There are ${bar} monkeys! Really 12 monkeys!")); + } + + { + std::string content = "There are ${foo} monkeys! Really ${foo} monkeys!"; + int rplc = dm.replaceExpressions(content); + assert(rplc == 2); + std::cout << content << std::endl; + assert(boost::equals(content, "There are 12 monkeys! Really 12 monkeys!")); + } +}
\ No newline at end of file diff --git a/test/src/test-predicates.cpp b/test/src/test-predicates.cpp index 954afb2..ff61f92 100644 --- a/test/src/test-predicates.cpp +++ b/test/src/test-predicates.cpp @@ -56,6 +56,7 @@ int main(int argc, char** argv) { assert(InterpreterImpl::nameMatch(transEvents, "foo.bar")); assert(!InterpreterImpl::nameMatch(transEvents, "errors.my.custom")); assert(!InterpreterImpl::nameMatch(transEvents, "errorhandler.mistake")); - assert(!InterpreterImpl::nameMatch(transEvents, "errOr.send")); + // is the event name case sensitive? + // assert(!InterpreterImpl::nameMatch(transEvents, "errOr.send")); assert(!InterpreterImpl::nameMatch(transEvents, "foobar")); }
\ No newline at end of file |