summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp')
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp409
1 files changed, 409 insertions, 0 deletions
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
new file mode 100644
index 0000000..e25ece4
--- /dev/null
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -0,0 +1,409 @@
+#include "uscxml/Common.h"
+#include "V8DataModel.h"
+#include "dom/V8SCXMLDOM.h"
+#include "uscxml/Message.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 V8DataModelProvider() );
+ return true;
+}
+#endif
+
+V8DataModel::V8DataModel() {
+// _contexts.push_back(v8::Context::New());
+}
+
+DataModel* V8DataModel::create(Interpreter* interpreter) {
+ V8DataModel* dm = new V8DataModel();
+ dm->_interpreter = interpreter;
+ v8::Locker locker;
+ v8::HandleScope scope;
+
+ // see http://stackoverflow.com/questions/3171418/v8-functiontemplate-class-instance
+// dm->_globalTemplate = v8::Persistent<v8::ObjectTemplate>(v8::ObjectTemplate::New());
+// dm->_globalTemplate->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast<void*>(this))));
+
+ v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+ global->Set(v8::String::New("In"), v8::FunctionTemplate::New(jsIn, v8::External::New(reinterpret_cast<void*>(dm))));
+ global->Set(v8::String::New("print"), v8::FunctionTemplate::New(jsPrint, v8::External::New(reinterpret_cast<void*>(dm))));
+ global->Set(v8::String::New("document"), V8SCXMLDOM::getDocument(interpreter->getDocument()));
+
+ dm->_contexts.push_back(v8::Context::New(NULL, global));
+ dm->setName(interpreter->getName());
+ dm->setSessionId(interpreter->getSessionId());
+ dm->eval("_ioprocessors = {};");
+
+ return dm;
+}
+
+void V8DataModel::setSessionId(const std::string& sessionId) {
+ _sessionId = sessionId;
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Object> global = _contexts.front()->Global();
+
+ global->Set(v8::String::New("_sessionid"), v8::String::New(sessionId.c_str()));
+}
+
+void V8DataModel::setName(const std::string& name) {
+ _name = name;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Object> global = _contexts.front()->Global();
+
+ global->Set(v8::String::New("_name"), v8::String::New(name.c_str()));
+}
+
+V8DataModel::~V8DataModel() {
+ while(_contexts.size() > 0) {
+ _contexts.back().Dispose();
+ _contexts.pop_back();
+ }
+}
+
+void V8DataModel::pushContext() {
+ _contexts.push_back(_contexts.back().New(_contexts.back()));
+}
+
+void V8DataModel::popContext() {
+ if (_contexts.size() > 1) {
+ _contexts.back().Dispose();
+ _contexts.pop_back();
+ }
+}
+
+void V8DataModel::initialize() {
+}
+
+void V8DataModel::setEvent(const Event& event) {
+ _event = event;
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Object> global = _contexts.front()->Global();
+
+ // this is unfortunate - can't we store the template in the object?
+ if (_eventTemplate.IsEmpty()) {
+ v8::Handle<v8::ObjectTemplate> localEventTemplate = v8::ObjectTemplate::New();
+ localEventTemplate->SetInternalFieldCount(1); // we only have a single C++ object
+ localEventTemplate->SetAccessor(v8::String::New("name"), V8DataModel::jsGetEventName);
+ localEventTemplate->SetAccessor(v8::String::New("type"), V8DataModel::jsGetEventType);
+ localEventTemplate->SetAccessor(v8::String::New("sendid"), V8DataModel::jsGetEventSendId);
+ localEventTemplate->SetAccessor(v8::String::New("origin"), V8DataModel::jsGetEventOrigin);
+ localEventTemplate->SetAccessor(v8::String::New("origintype"), V8DataModel::jsGetEventOriginType);
+ localEventTemplate->SetAccessor(v8::String::New("invokeid"), V8DataModel::jsGetEventInvokeId);
+ _eventTemplate = v8::Persistent<v8::ObjectTemplate>::New(localEventTemplate);
+ }
+
+ assert(_eventTemplate->InternalFieldCount() == 1);
+ v8::Handle<v8::Object> eventJS = _eventTemplate->NewInstance();
+ eventJS->SetInternalField(0, v8::External::New(&_event));
+
+ eventJS->Set(v8::String::New("data"), getDataAsValue(event)); // set data part of _event
+ global->Set(v8::String::New("_event"), eventJS);
+}
+
+Data V8DataModel::getStringAsData(const std::string& content) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+ v8::Handle<v8::Value> result = evalAsValue(content);
+ Data data = getValueAsData(result);
+ return data;
+}
+
+Data V8DataModel::getValueAsData(const v8::Handle<v8::Value>& value) {
+ Data data;
+ if (false) {
+ } else if (value->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+ for (int i = 0; i < array->Length(); i++) {
+ data.array.push_back(getValueAsData(array->Get(i)));
+ }
+ } else if (value->IsBoolean()) {
+ data.atom = (value->ToBoolean()->Value() ? "true" : "false");
+ } else if (value->IsBooleanObject()) {
+ LOG(ERROR) << "IsBooleanObject is unimplemented" << std::endl;
+ } else if (value->IsDate()) {
+ LOG(ERROR) << "IsDate is unimplemented" << std::endl;
+ } else if (value->IsExternal()) {
+ LOG(ERROR) << "IsExternal is unimplemented" << std::endl;
+ } else if (value->IsFalse()) {
+ LOG(ERROR) << "IsFalse is unimplemented" << std::endl;
+ } else if (value->IsFunction()) {
+ LOG(ERROR) << "IsFunction is unimplemented" << std::endl;
+ } else if (value->IsInt32()) {
+ int32_t prop = value->Int32Value();
+ data.atom = toStr(prop);
+ } else if (value->IsNativeError()) {
+ LOG(ERROR) << "IsNativeError is unimplemented" << std::endl;
+ } else if (value->IsNull()) {
+ LOG(ERROR) << "IsNull is unimplemented" << std::endl;
+ } else if (value->IsNumber()) {
+ v8::String::AsciiValue prop(v8::Handle<v8::String>::Cast(v8::Handle<v8::Number>::Cast(value)));
+ data.atom = *prop;
+ } else if (value->IsNumberObject()) {
+ LOG(ERROR) << "IsNumberObject is unimplemented" << std::endl;
+ } else if (value->IsObject()) {
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
+ v8::Local<v8::Array> properties = object->GetPropertyNames();
+ for (int i = 0; i < properties->Length(); i++) {
+ assert(properties->Get(i)->IsString());
+ v8::String::AsciiValue key(v8::Handle<v8::String>::Cast(properties->Get(i)));
+ v8::Local<v8::Value> property = object->Get(properties->Get(i));
+ data.compound[*key] = getValueAsData(property);
+ }
+ } else if (value->IsRegExp()) {
+ LOG(ERROR) << "IsRegExp is unimplemented" << std::endl;
+ } else if(value->IsString()) {
+ v8::String::AsciiValue property(v8::Handle<v8::String>::Cast(value));
+ data.atom = *property;
+ } else if(value->IsStringObject()) {
+ LOG(ERROR) << "IsStringObject is unimplemented" << std::endl;
+ } else if(value->IsTrue()) {
+ LOG(ERROR) << "IsTrue is unimplemented" << std::endl;
+ } else if(value->IsUint32()) {
+ LOG(ERROR) << "IsUint32 is unimplemented" << std::endl;
+ } else if(value->IsUndefined()) {
+ LOG(ERROR) << "IsUndefined is unimplemented" << std::endl;
+ }
+ return data;
+}
+
+v8::Handle<v8::Value> V8DataModel::getDataAsValue(const Data& data) {
+ if (data.compound.size() > 0) {
+ v8::Handle<v8::Object> value = v8::Object::New();
+ std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin();
+ while(compoundIter != data.compound.end()) {
+ value->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second));
+ compoundIter++;
+ }
+ return value;
+ }
+ if (data.array.size() > 0) {
+ v8::Handle<v8::Object> value = v8::Array::New();
+ std::list<Data>::const_iterator arrayIter = data.array.begin();
+ uint32_t index = 0;
+ while(arrayIter != data.array.end()) {
+ value->Set(index++, getDataAsValue(*arrayIter));
+ arrayIter++;
+ }
+ return value;
+ }
+ if (data.type == Data::VERBATIM) {
+ return v8::String::New(data.atom.c_str());
+ } else {
+ return evalAsValue(data.atom);
+ }
+}
+
+v8::Handle<v8::Value> V8DataModel::jsPrint(const v8::Arguments& args) {
+ if (args.Length() > 0) {
+ v8::String::AsciiValue printMsg(args[0]->ToString());
+ std::cout << *printMsg;
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> V8DataModel::jsIn(const v8::Arguments& args) {
+ V8DataModel* INSTANCE = static_cast<V8DataModel*>(v8::External::Unwrap(args.Data()));
+ for (unsigned int i = 0; i < args.Length(); i++) {
+ if (args[i]->IsString()) {
+ std::string stateName(*v8::String::AsciiValue(args[i]->ToString()));
+ if (Interpreter::isMember(INSTANCE->_interpreter->getState(stateName), INSTANCE->_interpreter->getConfiguration())) {
+ continue;
+ }
+ }
+ return v8::Boolean::New(false);
+ }
+ return v8::Boolean::New(true);
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventName(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->name.c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ switch (event->type) {
+ case Event::PLATFORM:
+ return v8::String::New("platform");
+ break;
+ case Event::INTERNAL:
+ return v8::String::New("internal");
+ break;
+ case Event::EXTERNAL:
+ return v8::String::New("external");
+ break;
+ default:
+ return v8::String::New("");
+ break;
+ }
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventSendId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->sendid.c_str());
+
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventOrigin(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->origin.c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventOriginType(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->origintype.c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::jsGetEventInvokeId(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info) {
+ Event* event = static_cast<Event*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value());
+ return v8::String::New(event->invokeid.c_str());
+}
+
+bool V8DataModel::validate(const std::string& location, const std::string& schema) {
+ return true;
+}
+
+uint32_t V8DataModel::getLength(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Array> result = evalAsValue(expr).As<v8::Array>();
+ return result->Length();
+}
+
+void V8DataModel::eval(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ evalAsValue(expr);
+}
+
+bool V8DataModel::evalAsBool(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Value> result = evalAsValue(expr);
+ return(result->ToBoolean()->BooleanValue());
+}
+
+std::string V8DataModel::evalAsString(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Value> result = evalAsValue(expr);
+ v8::String::AsciiValue data(result->ToString());
+ return std::string(*data);
+}
+
+void V8DataModel::assign(const std::string& location, const Data& data) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.front());
+
+ std::stringstream ssJSON;
+ ssJSON << data;
+ assign(location, ssJSON.str());
+// v8::Handle<v8::Object> variable = evalAsValue(location).As<v8::Object>();
+// assert(!variable.IsEmpty());
+// if (data.compound.size() > 0) {
+// std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin();
+// while(compoundIter != data.compound.end()) {
+// variable->Set(v8::String::New(compoundIter->first.c_str()), getDataAsValue(compoundIter->second));
+// compoundIter++;
+// }
+// return;
+// } else if (data.array.size() > 0) {
+// std::list<Data>::const_iterator arrayIter = data.array.begin();
+// uint32_t index = 0;
+// while(arrayIter != data.array.end()) {
+// variable->Set(index++, getDataAsValue(*arrayIter));
+// arrayIter++;
+// }
+// } else if (data.type == Data::VERBATIM) {
+// assign(location, "'" + data.atom + "'");
+// } else {
+// assign(location, data.atom);
+// }
+
+}
+
+void V8DataModel::assign(const std::string& location, const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ evalAsValue((location + " = " + expr).c_str());
+}
+
+v8::Handle<v8::Value> V8DataModel::evalAsValue(const std::string& expr) {
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::String> source = v8::String::New(expr.c_str());
+ v8::Handle<v8::Script> script = v8::Script::Compile(source);
+
+ v8::Handle<v8::Value> result;
+ if (!script.IsEmpty())
+ result = script->Run();
+
+ if (script.IsEmpty() || result.IsEmpty()) {
+ // throw an exception
+ assert(tryCatch.HasCaught());
+ Event exceptionEvent;
+ exceptionEvent.name = "error.execution";
+
+ std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception()));
+ exceptionEvent.compound["exception"] = Data(exceptionString, Data::VERBATIM);;
+
+ v8::Handle<v8::Message> message = tryCatch.Message();
+ if (!message.IsEmpty()) {
+ std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName()));
+ exceptionEvent.compound["filename"] = Data(filename, Data::VERBATIM);
+
+ std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine()));
+ exceptionEvent.compound["sourceline"] = Data(sourceLine, Data::VERBATIM);
+
+ std::stringstream ssLineNumber;
+ int lineNumber = message->GetLineNumber();
+ ssLineNumber << lineNumber;
+ exceptionEvent.compound["linenumber"] = Data(ssLineNumber.str());
+
+ int startColumn = message->GetStartColumn();
+ int endColumn = message->GetEndColumn();
+ std::stringstream ssUnderline;
+ for (int i = 0; i < startColumn; i++)
+ ssUnderline << " ";
+ for (int i = startColumn; i < endColumn; i++)
+ ssUnderline << "^";
+ exceptionEvent.compound["sourcemark"] = Data(ssUnderline.str(), Data::VERBATIM);
+
+ std::string stackTrace(*v8::String::AsciiValue(tryCatch.StackTrace()));
+ exceptionEvent.compound["stacktrace"] = Data(stackTrace, Data::VERBATIM);
+
+ }
+
+ _interpreter->receiveInternal(exceptionEvent);
+ throw(exceptionEvent);
+ }
+
+ return result;
+}
+
+} \ No newline at end of file