source: trunk/zoo-project/zoo-kernel/service_internal_ruby.c @ 937

Last change on this file since 937 was 917, checked in by djay, 6 years ago

Merge prototype-v0 branch in trunk

File size: 13.7 KB
Line 
1/*
2 * Author : Gérald FENOY
3 *
4 * Copyright (c) 2014 GeoLabs SARL
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "service_internal_ruby.h"
26
27#if RUBY_API_VERSION_MAJOR >= 2 || RUBY_API_VERSION_MINOR == 9
28int argc=0;
29char **argv=NULL;
30#endif
31
32/**
33 * Load a Ruby file then run the function corresponding to the service by
34 * passing the conf, inputs and outputs parameters by refernce as Ruby Hash.
35 *
36 * @param main_conf the conf maps containing the main.cfg settings
37 * @param request the map containing the HTTP request
38 * @param s the service structure
39 * @param real_inputs the maps containing the inputs
40 * @param real_outputs the maps containing the outputs
41 * @return SERVICE_SUCCEEDED or SERVICE_FAILED if the service run, -1
42 *  if the service failed to load or throw error at runtime.
43 */
44int zoo_ruby_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
45#if RUBY_API_VERSION_MAJOR >= 2 || RUBY_API_VERSION_MINOR == 9
46  ruby_sysinit(&argc,&argv);
47  RUBY_INIT_STACK;
48#endif
49  ruby_init();
50  maps* m=*main_conf;
51  maps* inputs=*real_inputs;
52  maps* outputs=*real_outputs;
53  map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
54  char *ntmp=tmp0->value;
55  map* tmp=NULL;
56  ruby_init_loadpath();
57  ruby_script("ZOO_EMBEDDED_ENV");
58 
59  VALUE klass=rb_define_module("Zoo");
60  rb_define_const(klass,"SERVICE_SUCCEEDED",INT2FIX(3));
61  rb_define_const(klass,"SERVICE_FAILED",INT2FIX(4));
62  typedef VALUE (*HOOK)(...);
63  rb_define_module_function(klass,"Translate",reinterpret_cast<HOOK>(RubyTranslate),-1);
64  rb_define_module_function(klass,"UpdateStatus",reinterpret_cast<HOOK>(RubyUpdateStatus),-1);
65
66  int error = 0;
67               
68  ID rFunc=Qnil;
69  tmp=getMap(s->content,"serviceProvider");
70  if(tmp!=NULL){
71#if RUBY_VERSION_MINOR == 8
72    const char* script = ruby_sourcefile = rb_source_filename(tmp->value);
73    rb_protect(LoadWrap, reinterpret_cast<VALUE>(script), &error);
74#else
75    rb_load_protect(rb_str_new2(tmp->value), 0, &error);
76#endif
77    if(error) {
78      ruby_trace_error(m);
79      return -1;
80    }
81#if RUBY_VERSION_MINOR == 8
82    ruby_exec();
83#else
84    ruby_exec_node(NULL);
85#endif
86  }
87  else{
88    map* err=createMap("text","Unable to parse serviceProvider please check your zcfg file.");
89    addToMap(err,"code","NoApplicableCode");
90    printExceptionReportResponse(m,err);
91    return -1;
92  }
93  int res=SERVICE_FAILED;
94  rFunc=rb_intern(s->name);
95  if(rFunc!=Qnil){
96    VALUE arg1=RubyHash_FromMaps(m);
97    VALUE arg2=RubyHash_FromMaps(inputs);
98    VALUE arg3=RubyHash_FromMaps(outputs);
99    VALUE rArgs[3]={arg1,arg2,arg3};
100    if (!rArgs)
101      return -1;
102    struct my_callback data;
103    data.obj=Qnil;
104    data.method_id=rFunc;
105    data.nargs=3;
106    data.args[0]=rArgs[0];
107    data.args[1]=rArgs[1];
108    data.args[2]=rArgs[2];
109    typedef VALUE (*HOOK)(VALUE);
110    VALUE tres=rb_protect(reinterpret_cast<HOOK>(FunCallWrap),(VALUE)(&data),&error);
111    if (TYPE(tres) == T_FIXNUM) {
112      res=FIX2INT(tres);
113      freeMaps(real_outputs);
114      free(*real_outputs);
115      freeMaps(main_conf);
116      free(*main_conf);
117      *main_conf=mapsFromRubyHash(arg1);
118      *real_outputs=mapsFromRubyHash(arg3);
119#ifdef DEBUG
120      dumpMaps(*main_conf);
121      dumpMaps(*real_outputs);
122#endif
123    }else{
124      ruby_trace_error(m);
125      res=-1;
126    }
127  }
128  else{
129    char tmpS[1024];
130    sprintf(tmpS, "Cannot find the %s function in the %s file.\n", s->name, tmp->value);
131    map* tmps=createMap("text",tmpS);
132    printExceptionReportResponse(m,tmps);
133    res=-1;
134  }
135  ruby_finalize();
136  return res;
137}
138
139/**
140 * Load a ruby file
141 *
142 * @arg the file to load
143 * @return Qnil
144 */
145VALUE LoadWrap(VALUE arg) {
146  const char *filename = reinterpret_cast<const char*>(arg);
147  rb_load_file(filename);
148  return Qnil;
149}
150
151/**
152 * Call a ruby function with parameters
153 *
154 * @arg the callback structure
155 * @return the value returned the called ruby function
156 */
157VALUE FunCallWrap(VALUE rdata) {
158  struct my_callback* data = (struct my_callback*) rdata;
159  return rb_funcall2(data->obj,data->method_id,data->nargs,data->args);
160}
161
162/**
163 * Print the Ruby Stack Trace in an ows:ExceptionReport XML Document
164 *
165 * @param m the conf maps containing the main.cfg settings
166 * @see printExceptionReportResponse
167 */
168void ruby_trace_error(maps* m){
169#if RUBY_VERSION_MINOR == 8
170  VALUE lasterr = rb_gv_get("$!");
171#else
172  VALUE lasterr = rb_errinfo();
173  VALUE ruby_errinfo = lasterr;
174#endif
175  VALUE message = rb_obj_as_string(lasterr);
176  VALUE lklass = rb_class_path(CLASS_OF(lasterr));
177#if RUBY_VERSION_MINOR == 8
178  char *trace=(char*)malloc((strlen(RSTRING(lklass)->ptr)+strlen(RSTRING(message)->ptr)+3)*sizeof(char));
179  sprintf(trace,"%s: %s",RSTRING_PTR(lklass),RSTRING_PTR(message));
180#else
181  char *trace=(char*)malloc((strlen(RSTRING_PTR(lklass))+strlen(RSTRING_PTR(message))+3)*sizeof(char));
182  sprintf(trace,"%s: %s",RSTRING_PTR(lklass),RSTRING_PTR(message));
183#endif
184  if(!NIL_P(ruby_errinfo))
185    {
186      VALUE ary = rb_funcall(ruby_errinfo, rb_intern("backtrace"), 0);
187      int c;
188      for (c=0; c<RARRAY_LEN(ary); c++) {
189        int len=strlen(trace);
190        char *tmp0=zStrdup(trace);
191#if RUBY_VERSION_MINOR == 8
192        trace=(char *) realloc(trace,(len+strlen(RSTRING(RARRAY(ary)->ptr[c])->ptr)+2)*sizeof(char));
193        sprintf(trace,"%s\n%s",tmp0,RSTRING(RARRAY(ary)->ptr[c])->ptr);
194#else
195        trace=(char *) realloc(trace,(len+strlen(RSTRING_PTR(RARRAY_PTR(ary)[c]))+2)*sizeof(char));
196        sprintf(trace,"%s\n%s",tmp0,RSTRING_PTR(RARRAY_PTR(ary)[c]));
197#endif
198        free(tmp0);
199      }
200    }
201  map* err=createMap("text",trace);
202  addToMap(err,"code","NoApplicableCode");
203  printExceptionReportResponse(m,err);
204}
205
206/**
207 * Convert a maps to a Ruby Hash
208 *
209 * @param t the maps to convert
210 * @return a new Ruby Hash
211 */
212VALUE RubyHash_FromMaps(maps* t){
213  VALUE res=rb_hash_new();
214  maps* tmp=t;
215  while(tmp!=NULL){
216    VALUE value=RubyHash_FromMap(tmp->content);
217    VALUE name=rb_str_new2(tmp->name);
218    rb_hash_aset(res,name,value);
219    tmp=tmp->next;
220  } 
221  return res;
222}
223
224/**
225 * Push the key on the array
226 *
227 * @param key the key to push
228 * @param value not used
229 * @param ary the Array
230 * @return ST_CONTINUE
231 */
232int
233keys_i(VALUE key,VALUE value,VALUE ary)
234{
235  if (key == Qundef) return ST_CONTINUE;
236  rb_ary_push(ary, key);
237  return ST_CONTINUE;
238}
239
240/**
241 * Return the size of a Ruby Hash
242 *
243 * @param hash the input Hash
244 */
245VALUE
246rb_hash_size(VALUE hash)
247{
248    return INT2FIX(RHASH_TBL(hash)->num_entries);
249}
250
251/**
252 * Convert a map to a Ruby Hash
253 *
254 * @param t the map to convert
255 * @return a new Ruby Hash
256 */
257VALUE RubyHash_FromMap(map* t){
258  VALUE res=rb_hash_new( );
259  map* tmp=t;
260  int hasSize=0;
261  map* isArray=getMap(tmp,"isArray");
262  map* useFile=getMap(tmp,"use_file");
263  map* size=getMap(tmp,"size");
264  map* tmap=getMapType(tmp);
265  while(tmp!=NULL){
266    VALUE name= rb_str_new2(tmp->name);
267    if(strcasecmp(tmp->name,"value")==0) {
268      if(isArray!=NULL){
269        map* len=getMap(tmp,"length");
270        int cnt=atoi(len->value);
271        VALUE value=rb_ary_new2(cnt);
272        VALUE mvalue=rb_ary_new2(cnt);
273        VALUE svalue=rb_ary_new2(cnt);
274        VALUE cvalue=rb_ary_new2(cnt);
275
276        for(int i=0;i<cnt;i++){
277         
278          map* vMap=getMapArray(tmp,"value",i);     
279          map* sMap=getMapArray(tmp,"size",i);
280          map* uMap=getMapArray(tmp,"use_file",i);
281          map* cMap=getMapArray(tmp,"cache_file",i);
282
283          if(vMap!=NULL){
284           
285            VALUE lvalue;
286            VALUE lsvalue;
287            VALUE lcvalue;
288            if(sMap==NULL || uMap==NULL){
289              lvalue=rb_str_new2(vMap->value);
290              if(sMap==NULL)
291                lsvalue=Qnil;
292              else
293                lsvalue=rb_str_new2(sMap->value);
294            }
295            else{
296              lvalue=rb_str_new(vMap->value,atoi(sMap->value));
297              lsvalue=rb_str_new2(sMap->value);
298              hasSize=1;
299            }
300            if(uMap!=NULL)
301              lcvalue=rb_str_new2(cMap->value);
302            else
303              lcvalue=Qnil;
304
305            rb_ary_push(value,lvalue);
306            rb_ary_push(svalue,lsvalue);
307            rb_ary_push(cvalue,lcvalue);
308          }
309         
310          map* mMap=getMapArray(tmp,tmap->name,i);
311
312          VALUE lmvalue;
313          if(mMap!=NULL){
314            lmvalue=rb_str_new2(mMap->value);
315          }else
316            lmvalue=Qnil;
317          rb_ary_push(mvalue,lmvalue);
318         
319        }
320
321        rb_hash_aset(res, name, mvalue);
322        rb_hash_aset(res, rb_str_new2(tmap->name), mvalue);
323        VALUE lname0=rb_str_new2("cache_size");
324        rb_hash_aset(res, lname0, value);
325     
326        if(hasSize>0){
327          VALUE lname=rb_str_new2("size");
328          rb_hash_aset(res, lname, value);
329        }
330      }
331      else if(size!=NULL){
332        VALUE value=rb_str_new(tmp->value,atoi(size->value));
333        rb_hash_aset(res, name, value);
334      }
335      else{
336        VALUE value=rb_str_new2(tmp->value);
337        rb_hash_aset(res, name, value);
338      }
339    }
340    else{
341      VALUE value=rb_str_new2(tmp->value);
342      rb_hash_aset(res, name, value);
343    }
344    tmp=tmp->next;
345  }
346  return res;
347}
348
349/**
350 * Convert a Ruby Hash to a maps
351 *
352 * @param t the Ruby Hash to convert
353 * @return a new maps
354 */
355maps* mapsFromRubyHash(VALUE t){
356  maps* res=NULL;
357  maps* cursor=res;
358  VALUE list;
359  list = rb_ary_new();
360  typedef int (*HOOK)(...);
361  rb_hash_foreach(t, reinterpret_cast<HOOK>(keys_i), list);
362  int nb=rb_hash_size(t);
363  int i;
364  for(i=0;i<FIX2INT(nb);i++){
365    VALUE key=rb_ary_pop(list);
366    VALUE value=rb_hash_aref(t,key);
367#ifdef DEBUG
368    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
369            StringValueCStr(key),StringValueCStr(value));
370#endif
371    cursor=createMaps(StringValueCStr(key));
372    cursor->content=mapFromRubyHash(value);
373    if(res==NULL)
374      res=dupMaps(&cursor);
375    else
376      addMapsToMaps(&res,cursor);
377    freeMaps(&cursor);
378    free(cursor);
379  }
380  return res;
381}
382
383/**
384 * Convert a Ruby Hash to a map
385 *
386 * @param t the Ruby Hash to convert
387 * @return a new map
388 */
389map* mapFromRubyHash(VALUE t){
390  map* res=NULL;
391  VALUE list;
392  list = rb_ary_new();
393  typedef int (*HOOK)(...);
394  rb_hash_foreach(t,reinterpret_cast<HOOK>(keys_i), list);
395  int nb=RHASH_TBL(t)->num_entries;
396  int i;
397  for(i=0;i<nb;i++){
398    VALUE key=rb_ary_pop(list);
399    VALUE value=rb_hash_aref(t,key);
400#ifdef DEBUG
401    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
402            StringValueCStr(key),StringValueCStr(value));
403#endif
404    if(strcmp(StringValueCStr(key),"value")==0){
405      char *buffer=NULL;
406      int size=RSTRING_LEN(value);
407      buffer=StringValueCStr(value);
408      if(res!=NULL){
409        addToMap(res,StringValueCStr(key),"");
410      }else{
411        res=createMap(StringValueCStr(key),"");
412      }
413      map* tmpR=getMap(res,"value");
414      free(tmpR->value);
415      tmpR->value=(char*)malloc((size+1)*sizeof(char));
416      memmove(tmpR->value,buffer,size*sizeof(char));
417      tmpR->value[size]=0;
418      char sin[1024];
419      sprintf(sin,"%d",size);
420      addToMap(res,"size",sin);
421    }else{
422      if(res!=NULL){
423        addToMap(res,StringValueCStr(key),StringValueCStr(value));
424      }
425      else{
426        res=
427          createMap(StringValueCStr(key),StringValueCStr(value));
428      }
429    }
430  }
431  return res;
432}
433
434/**
435 * Use the ZOO-Services messages translation function from the Ruby
436 * environment (ZOO-API)
437 *
438 * @param argc the number of parameters
439 * @param argv the parameter values given from the Ruby environment
440 * @param obj the Ruby object on which we run the method
441 * @return a new Ruby string containing the translated value
442 * @see _ss
443 */
444VALUE
445RubyTranslate(int argc, VALUE *argv, VALUE obj)
446{
447  return rb_str_new2(_ss(StringValueCStr(argv[0])));
448}
449
450/**
451 * Update the ongoing status of a running service from the Ruby environment
452 * (ZOO-API)
453 *
454 * @param argc the number of parameters
455 * @param argv the parameter values given from the Ruby environment
456 * @param obj the Ruby object on which we run the method
457 * @return a new Ruby string containing the translated value
458 * @see _updateStatus
459 */
460VALUE
461RubyUpdateStatus(int argc, VALUE *argv, VALUE obj)
462{
463  maps* conf;
464  VALUE confdict=argv[0];
465  int istatus=argv[1];
466  char* status;
467  if (istatus < 0 || istatus > 100){
468    fprintf(stderr,"Status must be a percentage.");
469    return Qnil;
470  }else{
471     char tmpStatus[4];
472     snprintf(tmpStatus, 4, "%i", istatus);
473     status = zStrdup(tmpStatus);
474  }
475  /* now update the map */
476  {
477    VALUE lenv = rb_hash_aref(confdict,rb_str_new2("lenv"));
478    if(TYPE(lenv)!=T_NIL){
479      VALUE valobj=rb_str_new2(status);
480      rb_hash_aset(lenv,rb_str_new2("status"),valobj);
481    }
482  }
483  conf = mapsFromRubyHash(confdict);
484  if (getMapFromMaps(conf,"lenv","status") != NULL){
485    fprintf(stderr,"STATUS RETURNED : %s\n",status);
486    if(status!=NULL){
487      setMapInMaps(conf,"lenv","status",status);
488      free(status);
489    }
490    else
491      setMapInMaps(conf,"lenv","status","15");
492    _updateStatus(conf);
493  }
494  freeMaps(&conf);
495  free(conf);
496  return Qnil;
497}
498
Note: See TracBrowser for help on using the repository browser.

Search

Context Navigation

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png