diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2012-12-15 19:10:50 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2012-12-15 19:10:50 (GMT) |
commit | f1700edcd08d6215888e226618555ba43b5324ec (patch) | |
tree | 738f30de64f699c3f56d2e15963537c9493a24b4 /src/uscxml/plugins/datamodel | |
parent | 2855a9ff7b423140237c9e988252fde0cbacd0a1 (diff) | |
download | uscxml-f1700edcd08d6215888e226618555ba43b5324ec.zip uscxml-f1700edcd08d6215888e226618555ba43b5324ec.tar.gz uscxml-f1700edcd08d6215888e226618555ba43b5324ec.tar.bz2 |
Refactoring and plugin support
Diffstat (limited to 'src/uscxml/plugins/datamodel')
4 files changed, 781 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 diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h new file mode 100644 index 0000000..994ed18 --- /dev/null +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h @@ -0,0 +1,92 @@ +#ifndef V8DATAMODEL_H_KN8TWG0V +#define V8DATAMODEL_H_KN8TWG0V + +#include "uscxml/Interpreter.h" +#include <list> +#include <v8.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + class Event; + class Data; + class V8SCXMLDOM; +} + +namespace uscxml { + +class V8DataModel : public DataModel { +public: + V8DataModel(); + virtual ~V8DataModel(); + virtual DataModel* create(Interpreter* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("ecmascript"); + return names; + } + + virtual void initialize(); + virtual void setSessionId(const std::string& sessionId); + virtual void setName(const std::string& name); + virtual void setEvent(const Event& event); + + virtual bool validate(const std::string& location, const std::string& schema); + + virtual uint32_t getLength(const std::string& expr); + virtual void pushContext(); + virtual void popContext(); + + virtual void eval(const std::string& expr); + virtual void assign(const std::string& location, const std::string& expr); + virtual void assign(const std::string& location, const Data& data); + + virtual Data getStringAsData(const std::string& content); + virtual Data getValueAsData(const v8::Handle<v8::Value>& value); + + virtual std::string evalAsString(const std::string& expr); + virtual bool evalAsBool(const std::string& expr); + + static v8::Handle<v8::Value> jsGetEventName(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventType(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventSendId(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventOrigin(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventOriginType(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsGetEventInvokeId(v8::Local<v8::String> property, + const v8::AccessorInfo &info); + + static v8::Handle<v8::Value> jsIn(const v8::Arguments& args); + static v8::Handle<v8::Value> jsPrint(const v8::Arguments& args); + + +protected: + std::list<v8::Persistent<v8::Context> > _contexts; + Interpreter* _interpreter; + + std::string _sessionId; + std::string _name; + + Event _event; + v8::Persistent<v8::ObjectTemplate> _globalTemplate; + v8::Persistent<v8::ObjectTemplate> _eventTemplate; + + v8::Handle<v8::Value> evalAsValue(const std::string& expr); + virtual v8::Handle<v8::Value> getDataAsValue(const Data& data); + +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(V8DataModel, DataModel); +#endif + +} + +#endif /* end of include guard: V8DATAMODEL_H_KN8TWG0V */ diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp new file mode 100644 index 0000000..6452330 --- /dev/null +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.cpp @@ -0,0 +1,219 @@ +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#endif +#include "V8SCXMLDOM.h" + +#define ASSERT_ARGS1(args, type1) \ +assert(args.Length() == 1); \ +assert(args[0]->type1()); + +#define ASSERT_ARGS2(args, type1, type2) \ +assert(args.Length() == 2); \ +assert(args[0]->type1()); \ +assert(args[1]->type2()); + +namespace uscxml { + + using namespace Arabica::DOM; + using namespace Arabica::XPath; + + V8SCXMLDOM::V8SCXMLDOM() { + } + + v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getDocument(Arabica::DOM::Document<std::string>& document) { + v8::Handle<v8::ObjectTemplate> documentTmpl = v8::ObjectTemplate::New(); + documentTmpl->Set(v8::String::New("createElement"), v8::FunctionTemplate::New(jsDocumentCreateElement, v8::External::New(reinterpret_cast<void*>(&document)))); + documentTmpl->Set(v8::String::New("evaluate"), v8::FunctionTemplate::New(jsDocumentEvaluate, v8::External::New(reinterpret_cast<void*>(&document)))); + return documentTmpl; + } + + v8::Handle<v8::Value> V8SCXMLDOM::jsDocumentCreateElement(const v8::Arguments& args) { + assert(!args.Data().IsEmpty()); + assert(args.Data()->IsExternal()); + + ASSERT_ARGS1(args, IsString) + + Document<std::string>* document = static_cast<Document<std::string>*>(v8::External::Unwrap(args.Data())); + v8::Persistent<v8::Object> elementJS = v8::Persistent<v8::Object>::New(getElementTmpl()->NewInstance()); + + v8::String::AsciiValue tagName(args[0]); + Element<std::string>* element = new Element<std::string>(document->createElement(*tagName)); + + elementJS->SetInternalField(0, v8::External::New(element)); + elementJS.MakeWeak(NULL, jsElementDestructor); + return elementJS; + } + + v8::Handle<v8::Value> V8SCXMLDOM::jsDocumentEvaluate(const v8::Arguments& args) { + assert(!args.Data().IsEmpty()); + assert(args.Data()->IsExternal()); + + assert(args.Length() > 0); + assert(args[0]->IsString()); + + + Document<std::string>* document = static_cast<Document<std::string>*>(v8::External::Unwrap(args.Data())); + Node<std::string> context; + if (args.Length() > 1) { + assert(args[1]->ToObject()->InternalFieldCount() == 1); + context = *static_cast<Node<std::string>*>(v8::Local<v8::External>::Cast(args[1]->ToObject()->GetInternalField(0))->Value()); + } else { + context = *document; + } + v8::String::AsciiValue xpathExpr(args[0]); + XPath<std::string> xpath; + XPathValue<std::string>* xpathValue = new XPathValue<std::string>(xpath.evaluate(*xpathExpr, context)); + + v8::Persistent<v8::Object> xpathValueJS = v8::Persistent<v8::Object>::New(getXPathValueTmpl()->NewInstance()); + xpathValueJS->SetInternalField(0, v8::External::New(xpathValue)); + xpathValueJS.MakeWeak(NULL, jsXPathValueDestructor); + return xpathValueJS; + } + + v8::Handle<v8::Value> V8SCXMLDOM::jsElementTagName(v8::Local<v8::String> property, const v8::AccessorInfo &info) { + Element<std::string>* element = static_cast<Element<std::string>*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + return v8::String::New(element->getTagName().c_str()); + } + + v8::Handle<v8::Value> V8SCXMLDOM::jsElementGetAttribute(const v8::Arguments& args) { + assert(!args.Data().IsEmpty()); + assert(args.Data()->IsExternal()); + + ASSERT_ARGS1(args, IsString); + + Element<std::string>* element = static_cast<Element<std::string>*>(v8::External::Unwrap(args.Data())); + + v8::String::AsciiValue attribute(args[0]); + if (element->hasAttribute(*attribute)) { + return v8::String::New(element->getAttribute(*attribute).c_str()); + } + return v8::String::New(""); + } + + v8::Handle<v8::Value> V8SCXMLDOM::jsElementSetAttribute(const v8::Arguments& args) { + v8::Local<v8::Object> self = args.Holder(); + assert(self->InternalFieldCount() == 1); + + ASSERT_ARGS2(args, IsString, IsString); + + v8::String::AsciiValue attribute(args[0]); + v8::String::AsciiValue value(args[1]); + + Element<std::string>* element = static_cast<Element<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); + element->setAttribute(*attribute, *value); + return v8::Undefined(); + } + + v8::Handle<v8::Value> V8SCXMLDOM::jsXPathValueAsNodeSet(const v8::Arguments& args) { + v8::Local<v8::Object> self = args.Holder(); + assert(self->InternalFieldCount() == 1); + XPathValue<std::string>* xPathValue = static_cast<XPathValue<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); + + v8::Persistent<v8::Object> nodeSetJS = v8::Persistent<v8::Object>::New(getNodeSetTmpl()->NewInstance()); + nodeSetJS->SetInternalField(0, v8::External::New(new NodeSet<std::string>(xPathValue->asNodeSet()))); + nodeSetJS.MakeWeak(NULL, jsNodeSetDestructor); + return nodeSetJS; + + } + + void V8SCXMLDOM::jsNodeSetDestructor(v8::Persistent<v8::Value> object, void* data) { + NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete nodeSet; + } + + void V8SCXMLDOM::jsNodeDestructor(v8::Persistent<v8::Value> object, void* data) { + Node<std::string>* node = static_cast<Node<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete node; + } + + void V8SCXMLDOM::jsXPathValueDestructor(v8::Persistent<v8::Value> object, void* data) { + XPathValue<std::string>* xPathValue = static_cast<XPathValue<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete xPathValue; + } + + void V8SCXMLDOM::jsElementDestructor(v8::Persistent<v8::Value> object, void* data) { + Element<std::string>* element = static_cast<Element<std::string>*>(v8::Local<v8::External>::Cast(object->ToObject()->GetInternalField(0))->Value()); + delete element; + } + + v8::Handle<v8::Value> V8SCXMLDOM::jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info) { + v8::Local<v8::Object> self = info.Holder(); + assert(self->InternalFieldCount() == 1); + NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::Local<v8::External>::Cast(info.Holder()->GetInternalField(0))->Value()); + + if (nodeSet->size() >= index) { + Node<std::string>* node = new Node<std::string>((*nodeSet)[index]); + v8::Persistent<v8::Object> nodeJS = v8::Persistent<v8::Object>::New(getNodeTmpl()->NewInstance()); + nodeJS->SetInternalField(0, v8::External::New(node)); + nodeJS.MakeWeak(NULL, jsNodeDestructor); + return nodeJS; + } + return v8::Undefined(); + } + + v8::Handle<v8::Value> V8SCXMLDOM::jsNodeSetLength(const v8::Arguments& args) { + v8::Local<v8::Object> self = args.Holder(); + assert(self->InternalFieldCount() == 1); + NodeSet<std::string>* nodeSet = static_cast<NodeSet<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); + return v8::Integer::New(nodeSet->size()); + } + + v8::Handle<v8::Value> V8SCXMLDOM::jsNodeAppendChild(const v8::Arguments& args) { + v8::Local<v8::Object> self = args.Holder(); + assert(self->InternalFieldCount() == 1); + Node<std::string>* node = static_cast<Node<std::string>*>(v8::External::Unwrap(self->GetInternalField(0))); + + assert(args.Length() == 1); + assert(args[0]->IsObject()); + + Node<std::string>* childToAppend = static_cast<Node<std::string>*>(v8::External::Unwrap(args[0]->ToObject()->GetInternalField(0))); + node->appendChild(*childToAppend); + + return v8::Undefined(); + } + + v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::xPathValueTmpl; + v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getXPathValueTmpl() { + if (xPathValueTmpl.IsEmpty()) { + xPathValueTmpl = v8::ObjectTemplate::New(); + xPathValueTmpl->SetInternalFieldCount(1); + xPathValueTmpl->Set(v8::String::New("asNodeSet"), v8::FunctionTemplate::New(jsXPathValueAsNodeSet)); + } + return xPathValueTmpl; + } + + v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::nodeSetTmpl; + v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getNodeSetTmpl() { + if (nodeSetTmpl.IsEmpty()) { + nodeSetTmpl = v8::ObjectTemplate::New(); + nodeSetTmpl->SetInternalFieldCount(1); + nodeSetTmpl->SetIndexedPropertyHandler(jsNodeSetGetIndex); + nodeSetTmpl->Set(v8::String::New("length"), v8::FunctionTemplate::New(jsNodeSetLength)); + } + return nodeSetTmpl; + } + + v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::nodeTmpl; + v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getNodeTmpl() { + if (nodeTmpl.IsEmpty()) { + nodeTmpl = v8::ObjectTemplate::New(); + nodeTmpl->SetInternalFieldCount(1); + nodeTmpl->Set(v8::String::New("appendChild"), v8::FunctionTemplate::New(jsNodeAppendChild)); + } + return nodeTmpl; + } + + v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::elementTmpl; + v8::Handle<v8::ObjectTemplate> V8SCXMLDOM::getElementTmpl() { + if (elementTmpl.IsEmpty()) { + elementTmpl = v8::ObjectTemplate::New(); + elementTmpl->SetAccessor(v8::String::New("tagName"), V8SCXMLDOM::jsElementTagName); + elementTmpl->Set(v8::String::New("getAttribute"), v8::FunctionTemplate::New(jsElementGetAttribute)); + elementTmpl->Set(v8::String::New("setAttribute"), v8::FunctionTemplate::New(jsElementSetAttribute)); + elementTmpl->SetInternalFieldCount(1); + } + return elementTmpl; + } + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h new file mode 100644 index 0000000..c513e48 --- /dev/null +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8SCXMLDOM.h @@ -0,0 +1,61 @@ +#ifndef V8SCXMLDOM_H_AREM0ZC4 +#define V8SCXMLDOM_H_AREM0ZC4 + +#include "uscxml/Interpreter.h" + +#include <DOM/Document.hpp> +#include <v8.h> + +#include <list> + +namespace uscxml { + +class V8SCXMLDOM { +public: + V8SCXMLDOM(); + virtual ~V8SCXMLDOM() {}; + + static v8::Handle<v8::ObjectTemplate> getDocument(Arabica::DOM::Document<std::string>& document); + static v8::Handle<v8::Value> jsDocumentCreateElement(const v8::Arguments& args); + static v8::Handle<v8::Value> jsDocumentEvaluate(const v8::Arguments& args); + + static v8::Handle<v8::Value> jsElementTagName(v8::Local<v8::String> property, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsElementGetAttribute(const v8::Arguments& args); + static v8::Handle<v8::Value> jsElementSetAttribute(const v8::Arguments& args); + static void jsElementDestructor(v8::Persistent<v8::Value> object, void* data); + + static v8::Handle<v8::Value> jsXPathValueAsNodeSet(const v8::Arguments& args); + static void jsXPathValueDestructor(v8::Persistent<v8::Value> object, void* data); + + static v8::Handle<v8::Value> jsNodeSetGetIndex(uint32_t index, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> jsNodeSetLength(const v8::Arguments& args); + static void jsNodeSetDestructor(v8::Persistent<v8::Value> object, void* data); + + static v8::Handle<v8::Value> jsNodeAppendChild(const v8::Arguments& args); + static void jsNodeDestructor(v8::Persistent<v8::Value> object, void* data); + + static v8::Handle<v8::ObjectTemplate> getXPathValueTmpl(); + static v8::Handle<v8::ObjectTemplate> getNodeSetTmpl(); + static v8::Handle<v8::ObjectTemplate> getNodeTmpl(); + static v8::Handle<v8::ObjectTemplate> getElementTmpl(); + + static v8::Handle<v8::ObjectTemplate> xPathValueTmpl; + static v8::Handle<v8::ObjectTemplate> nodeSetTmpl; + static v8::Handle<v8::ObjectTemplate> nodeTmpl; + static v8::Handle<v8::ObjectTemplate> elementTmpl; + +}; + +class V8Node { +}; + +class V8DOMDocument { + V8DOMDocument(); + virtual ~V8DOMDocument(); + + v8::Handle<v8::Array> jsChildNodes(); +}; + +} + +#endif /* end of include guard: V8SCXMLDOM_H_AREM0ZC4 */ |