RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/js/js_registry.cc
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
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator