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