JIMS: vectorize removing to avoid JNI overhead
[scilab.git] / scilab / modules / external_objects_java / src / cpp / ScilabJavaEnvironment.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2013 - Scilab Enterprises - Sylvestre LEDRU
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 #ifdef _MSC_VER
14 #include "windows.h"
15 #endif
16
17 #include <jni.h>
18
19 #include "ScilabJavaEnvironment.hxx"
20 #include "JavaOptionsHelper.hxx"
21 #include "ScilabClassLoader.hxx"
22 #include "ScilabJavaClass.hxx"
23 #include "ScilabJavaObject.hxx"
24 #include "ScilabJavaArray.hxx"
25 #include "ScilabJavaCompiler.hxx"
26 #include "ScilabOperations.hxx"
27 #include "NoMoreScilabMemoryException.hxx"
28 #include "ScilabAutoCleaner.hxx"
29
30 //#include "ScilabJavaObjectHelper.hxx"
31 extern "C" {
32 #include "getScilabJavaVM.h"
33 #include "tmpdir.h"
34 }
35
36 namespace org_scilab_modules_external_objects_java
37 {
38
39 const std::string ScilabJavaEnvironment::environmentName = "Java Environment";
40 int ScilabJavaEnvironment::envId = -1;
41 ScilabJavaEnvironment * ScilabJavaEnvironment::instance = 0;
42 bool ScilabJavaEnvironment::usable = true;
43
44 ScilabJavaEnvironment::ScilabJavaEnvironment() :
45     helper(*new JavaOptionsHelper()),
46     gwOptions(*new ScilabGatewayOptions()),
47     wrapper(*new ScilabJavaEnvironmentWrapper(helper)),
48     traceEnabled(false),
49     isInit(false),
50     scilabStream(*new ScilabStream()) { }
51
52 ScilabJavaEnvironment::~ScilabJavaEnvironment()
53 {
54     //    delete &scope;
55     delete &helper;
56     delete &gwOptions;
57     delete &wrapper;
58 }
59
60 int ScilabJavaEnvironment::start()
61 {
62     if (envId == -1)
63     {
64         instance = new ScilabJavaEnvironment();
65         envId = ScilabEnvironments::registerScilabEnvironment(instance);
66         instance->Initialize();
67         instance->helper.setUseLastName(true);
68         instance->helper.setNewAllowed(true);
69         //instance->enabletrace((std::string(getTMPDIR()) + std::string("/eo_java.log")).c_str());
70         //instance->enabletrace(std::string("/tmp/eo_java.log").c_str());
71     }
72
73     return envId;
74 }
75
76 void ScilabJavaEnvironment::finish()
77 {
78     if (envId != -1)
79     {
80         ScilabEnvironments::unregisterScilabEnvironment(envId);
81         envId = -1;
82         delete instance;
83         instance = 0;
84         instance->Finalize();
85         usable = false;
86     }
87 }
88
89 void ScilabJavaEnvironment::Initialize()
90 {
91     if (!isInit)
92     {
93         isInit = true;
94         // No need to init the Java VM. Scilab is already using it
95     }
96 }
97
98 void ScilabJavaEnvironment::Finalize()
99 {
100     // Scilab cannot kill the Java VM. It would probably crash the application
101 }
102
103 JavaOptionsHelper & ScilabJavaEnvironment::getOptionsHelper()
104 {
105     return helper;
106 }
107
108 ScilabGatewayOptions & ScilabJavaEnvironment::getGatewayOptions()
109 {
110     return gwOptions;
111 }
112
113 ScilabAbstractEnvironmentWrapper & ScilabJavaEnvironment::getWrapper()
114 {
115     return wrapper;
116 }
117
118 const std::string & ScilabJavaEnvironment::getEnvironmentName()
119 {
120     return environmentName;
121 }
122
123 void ScilabJavaEnvironment::getEnvironmentInfos(const ScilabStringStackAllocator & allocator)
124 {
125     JavaVM * vm = getScilabJavaVM();
126     int len;
127     char ** info = ScilabJavaObject::getInfos(vm, &len);
128
129     allocator.allocate(len, 1, info);
130
131     for (int i = 0; i < len; i++)
132     {
133         delete[] info[i];
134     }
135
136     delete[] info;
137 }
138
139 int ScilabJavaEnvironment::extract(int id, int * args, int argsSize)
140 {
141     JavaVM * vm = getScilabJavaVM();
142     const int ret = ScilabJavaObject::extract(vm, id, args, argsSize);
143
144     ScilabAutoCleaner::registerVariable(envId, ret);
145
146     return ret;
147 }
148
149 void ScilabJavaEnvironment::insert(int id, int * args, int argsSize)
150 {
151     JavaVM * vm = getScilabJavaVM();
152     ScilabJavaObject::insert(vm, id, args, argsSize - 1, args[argsSize - 1]);
153 }
154
155 void ScilabJavaEnvironment::garbagecollect()
156 {
157     JavaVM *vm = getScilabJavaVM();
158     ScilabJavaObject::garbageCollect(vm);
159 }
160
161 void ScilabJavaEnvironment::addtoclasspath(const char * path)
162 {
163     // Useless: we already have javaclasspath
164 }
165
166 void ScilabJavaEnvironment::getclasspath(const ScilabStringStackAllocator & allocator)
167 {
168     // Useless: we already have javaclasspath
169 }
170
171 void ScilabJavaEnvironment::addNamedVariable(int id, const char * varName)
172 {
173     // Useless in Java environment
174 }
175
176 int ScilabJavaEnvironment::getNamedVariable(const char * varName)
177 {
178     return 0;
179 }
180
181 void ScilabJavaEnvironment::evalString(const char ** code, int nbLines, ScilabStringStackAllocator * allocator)
182 {
183     // Useless in Java (it is not a script language !)
184 }
185
186 int ScilabJavaEnvironment::createarray(char * className, int * dims, int len)
187 {
188     JavaVM *vm = getScilabJavaVM();
189     const int ret = ScilabJavaArray::newInstance(vm, className, dims, len);
190
191     ScilabAutoCleaner::registerVariable(envId, ret);
192
193     return ret;
194 }
195
196 int ScilabJavaEnvironment::loadclass(char * className, char * currentSciPath, bool isNamedVarCreated, bool allowReload)
197 {
198     JavaVM *vm = getScilabJavaVM();
199     const int ret = ScilabClassLoader::loadJavaClass(vm, className, allowReload);
200
201     ScilabAutoCleaner::registerVariable(envId, ret);
202
203     return ret;
204 }
205
206 void ScilabJavaEnvironment::getrepresentation(int id, const ScilabStringStackAllocator & allocator)
207 {
208     JavaVM *vm = getScilabJavaVM();
209     char *str = ScilabJavaObject::getRepresentation(vm, id);
210     allocator.allocate(1, 1, &str);
211 }
212
213 std::string ScilabJavaEnvironment::getrepresentation(int id)
214 {
215     JavaVM *vm = getScilabJavaVM();
216     return std::string(ScilabJavaObject::getRepresentation(vm, id));
217 }
218
219 /* Used by jexists */
220 bool ScilabJavaEnvironment::isvalidobject(int id)
221 {
222     JavaVM *vm = getScilabJavaVM();
223     return ScilabJavaObject::isValidJavaObject(vm, id);
224 }
225
226 int ScilabJavaEnvironment::newinstance(int id, int * args, int argsSize)
227 {
228     JavaVM *vm = getScilabJavaVM();
229     const int ret = ScilabJavaClass::newInstance(vm, id, args, argsSize);
230
231     ScilabAutoCleaner::registerVariable(envId, ret);
232
233     return ret;
234 }
235
236 int ScilabJavaEnvironment::operation(int idA, int idB, const OperatorsType type)
237 {
238     JavaVM *vm = getScilabJavaVM();
239     int ret;
240
241     switch (type)
242     {
243         case Add :
244             ret = ScilabOperations::add(vm, idA, idB);
245             break;
246         default :
247             throw ScilabJavaException(__LINE__, __FILE__, gettext("Invalid operation"));
248     }
249
250     if (ret != 0 && ret != -1)
251     {
252         ScilabAutoCleaner::registerVariable(envId, ret);
253     }
254
255     return ret;
256 }
257
258 int * ScilabJavaEnvironment::invoke(int id, const char * methodName, int * args, int argsSize)
259 {
260     // TODO: In Java, an array can be passed as a reference so we need to "return" it
261     // for example, stream.read(buf, ...), the bytes are put in buf so we need to get it !
262
263     JavaVM *vm = getScilabJavaVM();
264     int * invokedId = new int[2];
265     invokedId[0] = 1 ; //1 object returned
266     invokedId[1] = ScilabJavaObject::invoke(vm, id, methodName, args, argsSize);
267
268     ScilabAutoCleaner::registerVariable(envId, invokedId[1]);
269
270     return invokedId;
271 }
272
273 void ScilabJavaEnvironment::setfield(int id, const char * fieldName, int idarg)
274 {
275     if (*fieldName == '\0')
276     {
277         throw ScilabJavaException(__LINE__, __FILE__, gettext("Invalid field name"));
278     }
279
280     try
281     {
282         JavaVM * vm = getScilabJavaVM();
283         ScilabJavaObject::setField(vm, id, fieldName, idarg);
284     }
285     catch (const GiwsException::JniCallMethodException & e)
286     {
287         throw ScilabJavaException(__LINE__, __FILE__, gettext("Cannot set the field: %s"), fieldName);
288     }
289 }
290
291 int ScilabJavaEnvironment::getfield(int id, const char * fieldName)
292 {
293     if (*fieldName == '\0')
294     {
295         throw ScilabJavaException(__LINE__, __FILE__, gettext("Invalid field name"));
296     }
297
298     JavaVM * vm = getScilabJavaVM();
299     const int ret = ScilabJavaObject::getField(vm, id, fieldName);
300
301     ScilabAutoCleaner::registerVariable(envId, ret);
302
303     return ret;
304 }
305
306 int ScilabJavaEnvironment::getfieldtype(int id, const char * fieldName)
307 {
308     JavaVM * vm = getScilabJavaVM();
309     return ScilabJavaObject::getFieldType(vm, id, fieldName);
310 }
311
312 int ScilabJavaEnvironment::getarrayelement(int id, int * index, int length)
313 {
314     JavaVM * vm = getScilabJavaVM();
315     const int ret = ScilabJavaObject::getArrayElement(vm, id, index, length);
316
317     ScilabAutoCleaner::registerVariable(envId, ret);
318
319     return ret;
320 }
321
322 void ScilabJavaEnvironment::setarrayelement(int id, int * index, int length, int idArg)
323 {
324     JavaVM * vm = getScilabJavaVM();
325     ScilabJavaObject::setArrayElement(vm, id, index, length, idArg);
326 }
327
328 int ScilabJavaEnvironment::cast(int id, char * className)
329 {
330     JavaVM *vm = getScilabJavaVM();
331     const int ret = ScilabJavaObject::javaCast(vm, id, className);
332
333     ScilabAutoCleaner::registerVariable(envId, ret);
334
335     return ret;
336 }
337
338 int ScilabJavaEnvironment::castwithid(int id, int classId)
339 {
340     JavaVM *vm = getScilabJavaVM();
341     const int ret = ScilabJavaObject::javaCast(vm, id, classId);
342
343     ScilabAutoCleaner::registerVariable(envId, ret);
344
345     return ret;
346 }
347
348 void ScilabJavaEnvironment::removeobject(int id)
349 {
350     JavaVM *vm = getScilabJavaVM();
351     ScilabJavaObject::removeScilabJavaObject(vm, id);
352     ScilabAutoCleaner::unregisterVariable(envId, id);
353 }
354
355 void ScilabJavaEnvironment::removeobject(const int * id, const int length)
356 {
357     if (length == 1)
358     {
359         removeobject(*id);
360     }
361     else
362     {
363         JavaVM *vm = getScilabJavaVM();
364         ScilabJavaObject::removeScilabJavaObject(vm, id, length);
365         ScilabAutoCleaner::unregisterVariable(envId, id, length);
366     }
367 }
368
369 void ScilabJavaEnvironment::autoremoveobject(int id)
370 {
371     JavaVM *vm = getScilabJavaVM();
372     ScilabJavaObject::removeScilabJavaObject(vm, id);
373 }
374
375 void ScilabJavaEnvironment::getaccessiblemethods(int id, const ScilabStringStackAllocator & allocator)
376 {
377     JavaVM *vm = getScilabJavaVM();
378     getMethodResult(vm, "getAccessibleMethods", id, allocator);
379 }
380
381 void ScilabJavaEnvironment::getaccessiblefields(int id, const ScilabStringStackAllocator & allocator)
382 {
383     JavaVM *vm = getScilabJavaVM();
384     getMethodResult(vm, "getAccessibleFields", id, allocator);
385     getAccessibleFields(id, allocator, true);
386 }
387
388 std::vector<std::string> ScilabJavaEnvironment::getCompletion(int id, char ** fieldsPath, const int fieldPathLen)
389 {
390     JavaVM * vm = getScilabJavaVM();
391     int len = 0;
392     char ** fields = ScilabJavaObject::getCompletion(vm, id, fieldsPath + 1 , fieldPathLen - 1, &len);
393     std::vector<std::string> v;
394
395     for (int i = 0; i < len; i++)
396     {
397         v.push_back(fields[i]);
398     }
399
400     return v;
401 }
402
403 std::string ScilabJavaEnvironment::getclassname(int id)
404 {
405     JavaVM *vm = getScilabJavaVM();
406     return std::string(ScilabJavaObject::getClassName(vm, id));
407 }
408
409 VariableType ScilabJavaEnvironment::isunwrappable(int id)
410 {
411     return wrapper.isunwrappable(id);
412 }
413
414 int ScilabJavaEnvironment::compilecode(char * className, char ** code, int size)
415 {
416     JavaVM *vm = getScilabJavaVM();
417     const int ret = ScilabJavaCompiler::compileCode(vm, className, code, size);
418
419     if (ret != 0 && ret != -1)
420     {
421         ScilabAutoCleaner::registerVariable(envId, ret);
422     }
423
424     return ret;
425 }
426
427 void ScilabJavaEnvironment::enabletrace(const char * filename)
428 {
429     JavaVM *vm = getScilabJavaVM();
430     ScilabJavaObject::enableTrace(vm, filename);
431     traceEnabled = true;
432 }
433
434 void ScilabJavaEnvironment::disabletrace(void)
435 {
436     JavaVM *vm = getScilabJavaVM();
437     ScilabJavaObject::disableTrace(vm);
438     traceEnabled = false;
439 }
440
441 void ScilabJavaEnvironment::writeLog(const std::string & fun, const std::string str, ...) const
442 {
443     if (traceEnabled)
444     {
445         JavaVM * vm = getScilabJavaVM();
446         char _str[LOG_BUFFER_SIZE];
447         va_list args;
448
449         va_start(args, str);
450         vsnprintf(_str, LOG_BUFFER_SIZE, str.c_str(), args);
451         va_end(args);
452
453         ScilabJavaObject::writeLog(vm, _str);
454     }
455 }
456
457 #define SCILABJAVAOBJECT "org/scilab/modules/external_objects_java/ScilabJavaObject"
458
459 void ScilabJavaEnvironment::getMethodResult(JavaVM * jvm_, const char * const methodName, int id, const ScilabStringStackAllocator & allocator)
460 {
461     JNIEnv * curEnv = NULL;
462     jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
463     jclass cls = curEnv->FindClass(SCILABJAVAOBJECT);
464     if (cls == NULL)
465     {
466         throw GiwsException::JniClassNotFoundException(curEnv, SCILABJAVAOBJECT);
467     }
468
469     jmethodID jobjectArray_getAccessibleMethodsjintID = curEnv->GetStaticMethodID(cls, methodName, "(I)[Ljava/lang/String;");
470     if (jobjectArray_getAccessibleMethodsjintID == NULL)
471     {
472         throw GiwsException::JniMethodNotFoundException(curEnv, methodName);
473     }
474
475     jobjectArray res = static_cast<jobjectArray>(curEnv->CallStaticObjectMethod(cls, jobjectArray_getAccessibleMethodsjintID, id));
476     if (curEnv->ExceptionCheck())
477     {
478         throw GiwsException::JniCallMethodException(curEnv);
479     }
480     jint lenRow = curEnv->GetArrayLength(res);
481     jboolean isCopy = JNI_FALSE;
482
483     char **addr = new char*[lenRow];
484     jstring *resString = new jstring[lenRow];
485
486     for (jsize i = 0; i < lenRow; i++)
487     {
488         resString[i] = reinterpret_cast<jstring>(curEnv->GetObjectArrayElement(res, i));
489         addr[i] = const_cast<char *>(curEnv->GetStringUTFChars(resString[i], &isCopy));
490     }
491     int lenCol = lenRow == 0 ? 0 : 1;
492     allocator.allocate(lenRow, lenCol, addr);
493     /*
494             SciErr err = createMatrixOfString(pvApiCtx, pos, lenCol, lenRow, addr);
495
496             for (jsize i = 0; i < lenRow; i++)
497             {
498                 curEnv->ReleaseStringUTFChars(resString[i], addr[i]);
499                 curEnv->DeleteLocalRef(resString[i]);
500                 }*/
501     delete[] addr;
502     delete[] resString;
503
504     // if (err.iErr)
505     // {
506     //     throw org_scilab_modules_external_objects_java::NoMoreScilabMemoryException();
507     // }
508
509     curEnv->DeleteLocalRef(res);
510     curEnv->DeleteLocalRef(cls);
511     if (curEnv->ExceptionCheck())
512     {
513         throw GiwsException::JniCallMethodException(curEnv);
514     }
515 };
516 }