![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* js_registry.cc 00002 Jeremy Barnes, 27 July 2010 00003 Copyright (c) 2010 Datacratic. All rights reserved. 00004 00005 Registry for Javascript templates. 00006 */ 00007 00008 #include "js_registry.h" 00009 #include "jml/arch/exception.h" 00010 #include <iostream> 00011 #include "js_utils.h" 00012 #include "jml/arch/backtrace.h" 00013 00014 using namespace std; 00015 using namespace v8; 00016 00017 00018 namespace Datacratic { 00019 namespace JS { 00020 00021 00022 /*****************************************************************************/ 00023 /* REGISTRY */ 00024 /*****************************************************************************/ 00025 00026 Registry:: 00027 Registry() 00028 : num_uninitialized(0) 00029 { 00030 } 00031 00032 Registry:: 00033 ~Registry() 00034 { 00035 // Close everything so that we can garbage collect them 00036 for (auto it = templates.begin(), end = templates.end(); 00037 it != end; ++it) 00038 it->second.tmpl.Dispose(); 00039 00040 templates.clear(); 00041 } 00042 00043 const v8::Persistent<v8::FunctionTemplate> & 00044 Registry:: 00045 operator [] (const std::string & name) const 00046 { 00047 auto it = templates.find(name); 00048 if (it == templates.end()) 00049 throw ML::Exception("didn't find required template " 00050 + name); 00051 00052 return it->second.tmpl; 00053 } 00054 00055 void 00056 Registry:: 00057 import(const Registry & other, const std::string & name) 00058 { 00059 if (templates.count(name)) 00060 throw ML::Exception("attempt to import JS template " 00061 + name + " a second time"); 00062 00063 auto it = other.templates.find(name); 00064 if (it == other.templates.end()) 00065 throw ML::Exception("attempt to import JS template " 00066 + name + " that doesn't exist"); 00067 00068 Entry entry = it->second; 00069 entry.imported = true; 00070 00071 templates[name] = entry; 00072 } 00073 00074 void 00075 Registry:: 00076 introduce(const std::string & name, 00077 const std::string & module, 00078 const InitFunction init, 00079 const std::string & base) 00080 { 00081 //cerr << "introduce " << name << " in module " << module 00082 // << " with base " << base << endl; 00083 00084 if (templates.count(name)) 00085 throw ML::Exception("attempt to introduce JS template " 00086 + name + " in module " + module 00087 + " a second time"); 00088 00089 Entry entry; 00090 entry.init = init; 00091 entry.base = base; 00092 entry.module = module; 00093 00094 templates[name] = entry; 00095 00096 ++num_uninitialized; 00097 00098 //cerr << "introduced " << name; 00099 //if (base != "") cerr << " based on " << base; 00100 //cerr << endl; 00101 } 00102 00103 void 00104 Registry:: 00105 get_to_know(const std::string & name, 00106 const std::string & module, 00107 const v8::Persistent<v8::FunctionTemplate> & tmpl, 00108 SetupFunction setup) 00109 { 00110 if (!templates.count(name)) 00111 throw ML::Exception("attempt to get_to_know function template " 00112 + name + " without introducing first"); 00113 00114 Entry & entry = templates[name]; 00115 00116 if (entry.module != module) 00117 throw ML::Exception("wrong module"); 00118 00119 entry.tmpl = tmpl; 00120 entry.setup = setup; 00121 entry.name = name; 00122 00123 templates[name] = entry; 00124 } 00125 00126 void 00127 Registry:: 00128 init(v8::Handle<v8::Object> target, const std::string & module) 00129 { 00130 if (num_uninitialized != 0) 00131 initialize(); 00132 00133 for (auto it = templates.begin(), end = templates.end(); it != end; ++it) 00134 if (!it->second.imported && it->second.module == module) 00135 it->second.setup(it->second.tmpl, it->second.name, target); 00136 } 00137 00138 00139 v8::Local<v8::Function> 00140 Registry:: 00141 getConstructor(const std::string & cls) const 00142 { 00143 const v8::Persistent<v8::FunctionTemplate> & tmpl = (*this)[cls]; 00144 return tmpl->GetFunction(); 00145 } 00146 00147 v8::Local<v8::Object> 00148 Registry:: 00149 constructInstance(const std::string & cls, OnConstructorError e) const 00150 { 00151 HandleScope scope; 00152 v8::Local<v8::Object> result = getConstructor(cls)->NewInstance(); 00153 if (result.IsEmpty() && e == THROW_ON_ERROR) 00154 throw JSPassException(); 00155 return scope.Close(result); 00156 } 00157 00158 v8::Local<v8::Object> 00159 Registry:: 00160 constructInstance(const std::string & cls, 00161 const v8::Arguments & args, 00162 OnConstructorError e) const 00163 { 00164 HandleScope scope; 00165 int argc = args.Length(); 00166 00167 vector<Handle<Value> > argv(argc); 00168 for (unsigned i = 0; i < argc; ++i) 00169 argv[i] = args[i]; 00170 00171 Local<Function> constructor = getConstructor(cls); 00172 00173 v8::Local<v8::Object> result 00174 = constructor->NewInstance(argc, &argv[0]); 00175 00176 if (result.IsEmpty() && e == THROW_ON_ERROR) 00177 throw JSPassException(); 00178 return scope.Close(result); 00179 } 00180 00181 v8::Local<v8::Object> 00182 Registry:: 00183 constructInstance(const std::string & cls, 00184 int argc, v8::Handle<v8::Value> * argv, 00185 OnConstructorError e) const 00186 { 00187 v8::Local<v8::Object> result = getConstructor(cls)->NewInstance(argc, argv); 00188 if (result.IsEmpty() && e == THROW_ON_ERROR) 00189 throw JSPassException(); 00190 return result; 00191 } 00192 00193 void 00194 Registry:: 00195 initialize() 00196 { 00197 for (auto it = templates.begin(), end = templates.end(); 00198 it != end; ++it) 00199 do_initialize(it->first); 00200 00201 if (num_uninitialized != 0) 00202 throw ML::Exception("initialize(): num_uninitialized was wrong"); 00203 } 00204 00205 void 00206 Registry:: 00207 do_initialize(const std::string & name) 00208 { 00209 auto it = templates.find(name); 00210 if (it == templates.end()) 00211 throw ML::Exception("didn't find required template " 00212 + name); 00213 00214 Entry & entry = it->second; 00215 00216 // Already done? Nothing else to do 00217 if (!entry.tmpl.IsEmpty()) return; 00218 00219 // Otherwise, first initialize its base 00220 if (entry.base != "") 00221 do_initialize(entry.base); 00222 00223 // And now initialize it 00224 entry.init(); 00225 00226 if (entry.tmpl.IsEmpty()) 00227 throw ML::Exception("wasn't initialized"); 00228 00229 --num_uninitialized; 00230 } 00231 00232 Registry registry; 00233 00234 00235 } // namespace JS 00236 } // namespace Datacratic