Osmium  0.1
include/osmium/HandlerJavascript.hpp
Go to the documentation of this file.
00001 #ifndef OSMIUM_HANDLER_JAVASCRIPT_HPP
00002 #define OSMIUM_HANDLER_JAVASCRIPT_HPP
00003 
00004 /*
00005 
00006 Copyright 2011 Jochen Topf <jochen@topf.org> and others (see README).
00007 
00008 This file is part of Osmium (https://github.com/joto/osmium).
00009 
00010 Osmium is free software: you can redistribute it and/or modify it under the
00011 terms of the GNU Lesser General Public License or (at your option) the GNU
00012 General Public License as published by the Free Software Foundation, either
00013 version 3 of the Licenses, or (at your option) any later version.
00014 
00015 Osmium is distributed in the hope that it will be useful, but WITHOUT ANY
00016 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
00017 PARTICULAR PURPOSE. See the GNU Lesser General Public License and the GNU
00018 General Public License for more details.
00019 
00020 You should have received a copy of the Licenses along with Osmium. If not, see
00021 <http://www.gnu.org/licenses/>.
00022 
00023 */
00024 
00025 #include <fstream>
00026 #include <iostream>
00027 #include <v8.h>
00028 
00029 extern v8::Persistent<v8::Context> global_context;
00030 
00031 namespace Osmium {
00032 
00033     namespace Handler {
00034 
00035         class Javascript : public Base {
00036 
00037             /***
00038             * Load Javascript file into string
00039             */
00040             static std::string load_file(const char* filename) {
00041                 std::ifstream javascript_file(filename, std::ifstream::in);
00042                 if (javascript_file.fail()) {
00043                     std::cerr << "Can't open file " << filename << std::endl;
00044                     exit(1);
00045                 }
00046                 std::stringstream buffer;
00047                 buffer << javascript_file.rdbuf();
00048                 return buffer.str();
00049             }
00050 
00051             static const char* ToCString(const v8::String::Utf8Value& value) {
00052                 return *value ? *value : "<string conversion failed>";
00053             }
00054 
00058             static void report_exception(v8::TryCatch* try_catch) {
00059                 v8::HandleScope handle_scope;
00060                 v8::String::Utf8Value exception(try_catch->Exception());
00061                 const char* exception_string = ToCString(exception);
00062 
00063                 v8::Handle<v8::Message> message = try_catch->Message();
00064                 if (message.IsEmpty()) {
00065                     std::cerr << exception_string << std::endl;
00066                 } else {
00067                     v8::String::Utf8Value filename(message->GetScriptResourceName());
00068                     std::cerr << *filename << ":" << message->GetLineNumber() << ": " << exception_string << std::endl;
00069 
00070                     v8::String::Utf8Value sourceline(message->GetSourceLine());
00071                     std::cerr << *sourceline << std::endl;
00072 
00073                     int start = message->GetStartColumn();
00074                     int end = message->GetEndColumn();
00075                     for (int i = 0; i < start; i++) {
00076                         std::cerr << " ";
00077                     }
00078                     for (int i = start; i < end; i++) {
00079                         std::cerr << "^";
00080                     }
00081                     std::cerr << std::endl;
00082                 }
00083             }
00084 
00085 
00086             v8::Persistent<v8::Object> callbacks_object;
00087             v8::Persistent<v8::Object> osmium_object;
00088 
00089             struct js_cb {
00090                 v8::Handle<v8::Function> init;
00091                 v8::Handle<v8::Function> node;
00092                 v8::Handle<v8::Function> way;
00093                 v8::Handle<v8::Function> relation;
00094                 v8::Handle<v8::Function> area;
00095                 v8::Handle<v8::Function> end;
00096             } cb;
00097 
00098         public:
00099 
00100             static v8::Handle<v8::Value> Print(const v8::Arguments& args) {
00101                 v8::HandleScope handle_scope;
00102 
00103                 for (int i = 0; i < args.Length(); i++) {
00104                     Osmium::v8_String_to_ostream(args[i]->ToString(), std::cout);
00105                     std::cout << "\n";
00106                 }
00107 
00108                 return handle_scope.Close(v8::Integer::New(1));
00109             }
00110 
00111             static v8::Handle<v8::Value> Include(const v8::Arguments& args) {
00112                 for (int i=0; i < args.Length(); i++) {
00113                     v8::String::Utf8Value filename(args[i]);
00114 
00115                     std::string javascript_source = load_file(*filename);
00116 
00117                     if (javascript_source.length() > 0) {
00118                         v8::TryCatch tryCatch;
00119 
00120                         v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(javascript_source.c_str()), v8::String::New(*filename));
00121                         if (script.IsEmpty()) {
00122                             std::cerr << "Compiling included script failed:" << std::endl;
00123                             report_exception(&tryCatch);
00124                             exit(1);
00125                         }
00126 
00127                         v8::Handle<v8::Value> result = script->Run();
00128                         if (result.IsEmpty()) {
00129                             std::cerr << "Running included script failed:" << std::endl;
00130                             report_exception(&tryCatch);
00131                             exit(1);
00132                         }
00133                     }
00134                 }
00135                 return v8::Undefined();
00136             }
00137 
00138             static v8::Handle<v8::Value> OutputCSVOpen(const v8::Arguments& args) {
00139                 if (args.Length() != 1) {
00140                     return v8::Undefined();
00141                 } else {
00142                     v8::String::Utf8Value str(args[0]);
00143                     Osmium::Export::CSV* oc = new Osmium::Export::CSV(*str);
00144                     return oc->js_instance();
00145                 }
00146             }
00147 
00148 #ifdef OSMIUM_WITH_SHPLIB
00149             static v8::Handle<v8::Value> OutputShapefileOpen(const v8::Arguments& args) {
00150                 if (args.Length() != 2) {
00151                     return v8::Undefined();
00152                 } else {
00153                     v8::String::Utf8Value str(args[0]);
00154                     v8::String::AsciiValue type(args[1]);
00155                     std::string filename(*str);
00156                     Osmium::Export::Shapefile* oc;
00157                     if (!strcmp(*type, "point")) {
00158                         oc = new Osmium::Export::PointShapefile(filename);
00159                     } else if (!strcmp(*type, "line")) {
00160                         oc = new Osmium::Export::LineStringShapefile(filename);
00161                     } else if (!strcmp(*type, "polygon")) {
00162                         oc = new Osmium::Export::PolygonShapefile(filename);
00163                     } else {
00164                         throw std::runtime_error("unknown shapefile type");
00165                     }
00166 
00167                     return oc->js_instance();
00168                 }
00169             }
00170 #endif // OSMIUM_WITH_SHPLIB
00171 
00172             Javascript(std::vector<std::string> include_files, const char* filename) : Base() {
00173 //                v8::HandleScope handle_scope;
00174                 v8::Handle<v8::String> init_source = v8::String::New("Osmium = { Callbacks: {}, Output: { } };");
00175                 v8::Handle<v8::Script> init_script = v8::Script::Compile(init_source);
00176                 osmium_object = v8::Persistent<v8::Object>::New(init_script->Run()->ToObject());
00177                 v8::Handle<v8::Object> output_object = osmium_object->Get(v8::String::NewSymbol("Output"))->ToObject();
00178 
00179                 osmium_object->Set(v8::String::NewSymbol("debug"), v8::Boolean::New(Osmium::debug()));
00180 
00181                 v8::Handle<v8::ObjectTemplate> output_csv_template = v8::ObjectTemplate::New();
00182                 output_csv_template->Set(v8::String::NewSymbol("open"), v8::FunctionTemplate::New(OutputCSVOpen));
00183                 output_object->Set(v8::String::NewSymbol("CSV"), output_csv_template->NewInstance());
00184 
00185 #ifdef OSMIUM_WITH_SHPLIB
00186                 v8::Handle<v8::ObjectTemplate> output_shapefile_template = v8::ObjectTemplate::New();
00187                 output_shapefile_template->Set(v8::String::NewSymbol("open"), v8::FunctionTemplate::New(OutputShapefileOpen));
00188                 output_object->Set(v8::String::NewSymbol("Shapefile"), output_shapefile_template->NewInstance());
00189 #endif // OSMIUM_WITH_SHPLIB
00190 
00191                 v8::Handle<v8::Object> callbacks_object = osmium_object->Get(v8::String::NewSymbol("Callbacks"))->ToObject();
00192 
00193                 v8::TryCatch tryCatch;
00194 
00195                 for (std::vector<std::string>::const_iterator vi(include_files.begin()); vi != include_files.end(); vi++) {
00196                     if (Osmium::debug()) {
00197                         std::cerr << "include javascript file: " << *vi << std::endl;
00198                     }
00199                     std::string javascript_source = load_file((*vi).c_str());
00200                     v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(javascript_source.c_str()), v8::String::New((*vi).c_str()));
00201                     if (script.IsEmpty()) {
00202                         std::cerr << "Compiling script failed:" << std::endl;
00203                         report_exception(&tryCatch);
00204                         exit(1);
00205                     }
00206 
00207                     v8::Handle<v8::Value> result = script->Run();
00208                     if (result.IsEmpty()) {
00209                         std::cerr << "Running script failed:" << std::endl;
00210                         report_exception(&tryCatch);
00211                         exit(1);
00212                     }
00213                 }
00214 
00215                 std::string javascript_source = load_file(filename);
00216                 if (javascript_source.length() == 0) {
00217                     std::cerr << "Javascript file " << filename << " is empty" << std::endl;
00218                     exit(1);
00219                 }
00220 
00221                 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(javascript_source.c_str()), v8::String::New(filename));
00222                 if (script.IsEmpty()) {
00223                     std::cerr << "Compiling script failed:" << std::endl;
00224                     report_exception(&tryCatch);
00225                     exit(1);
00226                 }
00227 
00228                 v8::Handle<v8::Value> result = script->Run();
00229                 if (result.IsEmpty()) {
00230                     std::cerr << "Running script failed:" << std::endl;
00231                     report_exception(&tryCatch);
00232                     exit(1);
00233                 }
00234 
00235                 v8::Handle<v8::Value> cc;
00236 
00237                 cc = callbacks_object->Get(v8::String::NewSymbol("init"));
00238                 if (cc->IsFunction()) {
00239                     cb.init = v8::Handle<v8::Function>::Cast(cc);
00240                 }
00241                 cc = callbacks_object->Get(v8::String::NewSymbol("node"));
00242                 if (cc->IsFunction()) {
00243                     cb.node = v8::Handle<v8::Function>::Cast(cc);
00244                 }
00245                 cc = callbacks_object->Get(v8::String::NewSymbol("way"));
00246                 if (cc->IsFunction()) {
00247                     cb.way = v8::Handle<v8::Function>::Cast(cc);
00248                 }
00249                 cc = callbacks_object->Get(v8::String::NewSymbol("relation"));
00250                 if (cc->IsFunction()) {
00251                     cb.relation = v8::Handle<v8::Function>::Cast(cc);
00252                 }
00253                 cc = callbacks_object->Get(v8::String::NewSymbol("area"));
00254                 if (cc->IsFunction()) {
00255                     cb.area = v8::Handle<v8::Function>::Cast(cc);
00256                 }
00257                 cc = callbacks_object->Get(v8::String::NewSymbol("end"));
00258                 if (cc->IsFunction()) {
00259                     cb.end = v8::Handle<v8::Function>::Cast(cc);
00260                 }
00261             }
00262 
00263             ~Javascript() {
00264                 callbacks_object.Dispose();
00265             }
00266 
00267             void init(Osmium::OSM::Meta&) {
00268                 if (!cb.init.IsEmpty()) {
00269                     (void) cb.init->Call(cb.init, 0, 0);
00270                 }
00271             }
00272 
00273             void node(const shared_ptr<Osmium::OSM::Node const>& node) {
00274                 if (!cb.node.IsEmpty()) {
00275                     (void) cb.node->Call(node->get_instance(), 0, 0);
00276                 }
00277 #ifdef OSMIUM_V8_FORCE_GC
00278                 while (!v8::V8::IdleNotification()) { };
00279 #endif // OSMIUM_V8_FORCE_GC
00280             }
00281 
00282             void way(const shared_ptr<Osmium::OSM::Way const>& way) {
00283                 if (!cb.way.IsEmpty()) {
00284                     (void) cb.way->Call(way->get_instance(), 0, 0);
00285                 }
00286 #ifdef OSMIUM_V8_FORCE_GC
00287                 while (!v8::V8::IdleNotification()) { };
00288 #endif // OSMIUM_V8_FORCE_GC
00289             }
00290 
00291             void relation(const shared_ptr<Osmium::OSM::Relation const>& relation) {
00292                 if (!cb.relation.IsEmpty()) {
00293                     (void) cb.relation->Call(relation->get_instance(), 0, 0);
00294                 }
00295 #ifdef OSMIUM_V8_FORCE_GC
00296                 while (!v8::V8::IdleNotification()) { };
00297 #endif // OSMIUM_V8_FORCE_GC
00298             }
00299 
00300             void area(Osmium::OSM::Area* area) {
00301                 if (!cb.area.IsEmpty()) {
00302                     (void) cb.area->Call(area->get_instance(), 0, 0);
00303                 }
00304 #ifdef OSMIUM_V8_FORCE_GC
00305                 while (!v8::V8::IdleNotification()) { };
00306 #endif // OSMIUM_V8_FORCE_GC
00307             }
00308 
00309             void final() {
00310                 if (!cb.end.IsEmpty()) {
00311                     (void) cb.end->Call(cb.end, 0, 0);
00312                 }
00313             }
00314 
00315         }; // class Javascript
00316 
00317     } // namespace Handler
00318 
00319 } // namespace Osmium
00320 
00321 #endif // OSMIUM_HANDLER_JAVASCRIPT_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines