f74b1d6e1e417f588a8aa730ebe058a0651ed72e
[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 "NoMoreScilabMemoryException.hxx"
27 #include "ScilabAutoCleaner.hxx"
28
29 //#include "ScilabJavaObjectHelper.hxx"
30 extern "C" {
31 #include "getScilabJavaVM.h"
32 #include "tmpdir.h"
33 }
34
35 namespace org_scilab_modules_external_objects_java
36 {
37
38 const std::string ScilabJavaEnvironment::environmentName = "Java Environment";
39 int ScilabJavaEnvironment::envId = -1;
40 ScilabJavaEnvironment * ScilabJavaEnvironment::instance = 0;
41 bool ScilabJavaEnvironment::usable = true;
42
43 ScilabJavaEnvironment::ScilabJavaEnvironment() :
44     helper(*new JavaOptionsHelper()),
45     gwOptions(*new ScilabGatewayOptions()),
46     wrapper(*new ScilabJavaEnvironmentWrapper(helper)),
47     traceEnabled(false),
48     isInit(false),
49     scilabStream(*new ScilabStream()) { }
50
51 ScilabJavaEnvironment::~ScilabJavaEnvironment()
52 {
53     //    delete &scope;
54     delete &helper;
55     delete &gwOptions;
56     delete &wrapper;
57 }
58
59 int ScilabJavaEnvironment::start()
60 {
61     if (envId == -1)
62     {
63         instance = new ScilabJavaEnvironment();
64         envId = ScilabEnvironments::registerScilabEnvironment(instance);
65         instance->Initialize();
66         instance->helper.setUseLastName(true);
67         instance->helper.setNewAllowed(true);
68         instance->enabletrace((std::string(getTMPDIR()) + std::string("/eo_java.log")).c_str());
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         delete instance;
81         instance = 0;
82         instance->Finalize();
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     // TODO: plug String concatenation and maybe others things like operations on double, int, ...
237
238     return 0;
239 }
240
241 int * ScilabJavaEnvironment::invoke(int id, const char * methodName, int * args, int argsSize)
242 {
243     // TODO: In Java, an array can be passed as a reference so we need to "return" it
244     // for example, stream.read(buf, ...), the bytes are put in buf so we need to get it !
245
246     JavaVM *vm = getScilabJavaVM();
247     int * invokedId = new int[2];
248     invokedId[0] = 1 ; //1 object returned
249     invokedId[1] = ScilabJavaObject::invoke(vm, id, methodName, args, argsSize);
250
251     ScilabAutoCleaner::registerVariable(envId, invokedId[1]);
252
253     return invokedId;
254 }
255
256 void ScilabJavaEnvironment::setfield(int id, const char * fieldName, int idarg)
257 {
258     if (*fieldName == '\0')
259     {
260         throw ScilabJavaException(__LINE__, __FILE__, gettext("Invalid field name"));
261     }
262
263     try
264     {
265         JavaVM * vm = getScilabJavaVM();
266         ScilabJavaObject::setField(vm, id, fieldName, idarg);
267     }
268     catch (const GiwsException::JniCallMethodException & e)
269     {
270         throw ScilabJavaException(__LINE__, __FILE__, gettext("Cannot set the field: %s"), fieldName);
271     }
272 }
273
274 int ScilabJavaEnvironment::getfield(int id, const char * fieldName)
275 {
276     if (*fieldName == '\0')
277     {
278         throw ScilabJavaException(__LINE__, __FILE__, gettext("Invalid field name"));
279     }
280
281     JavaVM * vm = getScilabJavaVM();
282     const int ret = ScilabJavaObject::getField(vm, id, fieldName);
283
284     ScilabAutoCleaner::registerVariable(envId, ret);
285
286     return ret;
287 }
288
289 int ScilabJavaEnvironment::getfieldtype(int id, const char * fieldName)
290 {
291     JavaVM * vm = getScilabJavaVM();
292     return ScilabJavaObject::getFieldType(vm, id, fieldName);
293 }
294
295 int ScilabJavaEnvironment::getarrayelement(int id, int * index, int length)
296 {
297     JavaVM * vm = getScilabJavaVM();
298     const int ret = ScilabJavaObject::getArrayElement(vm, id, index, length);
299
300     ScilabAutoCleaner::registerVariable(envId, ret);
301
302     return ret;
303 }
304
305 void ScilabJavaEnvironment::setarrayelement(int id, int * index, int length, int idArg)
306 {
307     JavaVM * vm = getScilabJavaVM();
308     ScilabJavaObject::setArrayElement(vm, id, index, length, idArg);
309 }
310
311 int ScilabJavaEnvironment::cast(int id, char * className)
312 {
313     JavaVM *vm = getScilabJavaVM();
314     const int ret = ScilabJavaObject::javaCast(vm, id, className);
315
316     ScilabAutoCleaner::registerVariable(envId, ret);
317
318     return ret;
319 }
320
321 int ScilabJavaEnvironment::castwithid(int id, int classId)
322 {
323     JavaVM *vm = getScilabJavaVM();
324     const int ret = ScilabJavaObject::javaCast(vm, id, classId);
325
326     ScilabAutoCleaner::registerVariable(envId, ret);
327
328     return ret;
329 }
330
331 void ScilabJavaEnvironment::removeobject(int id)
332 {
333     JavaVM *vm = getScilabJavaVM();
334     ScilabJavaObject::removeScilabJavaObject(vm, id);
335     ScilabAutoCleaner::unregisterVariable(envId, id);
336 }
337
338 void ScilabJavaEnvironment::autoremoveobject(int id)
339 {
340     JavaVM *vm = getScilabJavaVM();
341     ScilabJavaObject::removeScilabJavaObject(vm, id);
342 }
343
344 void ScilabJavaEnvironment::getaccessiblemethods(int id, const ScilabStringStackAllocator & allocator)
345 {
346     JavaVM *vm = getScilabJavaVM();
347     getMethodResult(vm, "getAccessibleMethods", id, allocator);
348 }
349
350 void ScilabJavaEnvironment::getaccessiblefields(int id, const ScilabStringStackAllocator & allocator)
351 {
352     JavaVM *vm = getScilabJavaVM();
353     getMethodResult(vm, "getAccessibleFields", id, allocator);
354     getAccessibleFields(id, allocator, true);
355 }
356
357 std::vector<std::string> ScilabJavaEnvironment::getCompletion(int id, char ** fieldsPath, const int fieldPathLen)
358 {
359     JavaVM * vm = getScilabJavaVM();
360     int len = 0;
361     char ** fields = ScilabJavaObject::getCompletion(vm, id, fieldsPath + 1 , fieldPathLen - 1, &len);
362     std::vector<std::string> v;
363
364     for (int i = 0; i < len; i++)
365     {
366         v.push_back(fields[i]);
367     }
368
369     return v;
370 }
371
372 std::string ScilabJavaEnvironment::getclassname(int id)
373 {
374     JavaVM *vm = getScilabJavaVM();
375     return std::string(ScilabJavaObject::getClassName(vm, id));
376 }
377
378 VariableType ScilabJavaEnvironment::isunwrappable(int id)
379 {
380     return wrapper.isunwrappable(id);
381 }
382
383 int ScilabJavaEnvironment::compilecode(char * className, char ** code, int size)
384 {
385     std::ostringstream os;
386     for (int i = 0; i < size; i++)
387     {
388         os << code[i] << std::endl;
389     }
390     os.flush();
391
392     JavaVM *vm = getScilabJavaVM();
393     const int ret = ScilabJavaCompiler::compileCode(vm, className, code, size);
394
395     ScilabAutoCleaner::registerVariable(envId, ret);
396
397     return ret;
398 }
399
400 void ScilabJavaEnvironment::enabletrace(const char * filename)
401 {
402     JavaVM *vm = getScilabJavaVM();
403     ScilabJavaObject::enableTrace(vm, filename);
404     traceEnabled = true;
405 }
406
407 void ScilabJavaEnvironment::disabletrace(void)
408 {
409     JavaVM *vm = getScilabJavaVM();
410     ScilabJavaObject::disableTrace(vm);
411     traceEnabled = false;
412 }
413
414 void ScilabJavaEnvironment::writeLog(const std::string & fun, const std::string str, ...) const
415 {
416     if (traceEnabled)
417     {
418         JavaVM * vm = getScilabJavaVM();
419         char _str[LOG_BUFFER_SIZE];
420         va_list args;
421
422         va_start(args, str);
423         vsnprintf(_str, LOG_BUFFER_SIZE, str.c_str(), args);
424         va_end(args);
425
426         ScilabJavaObject::writeLog(vm, _str);
427     }
428 }
429
430 #define SCILABJAVAOBJECT "org/scilab/modules/external_objects_java/ScilabJavaObject"
431
432 void ScilabJavaEnvironment::getMethodResult(JavaVM * jvm_, const char * const methodName, int id, const ScilabStringStackAllocator & allocator)
433 {
434     JNIEnv * curEnv = NULL;
435     jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
436     jclass cls = curEnv->FindClass(SCILABJAVAOBJECT);
437     if (cls == NULL)
438     {
439         throw GiwsException::JniClassNotFoundException(curEnv, SCILABJAVAOBJECT);
440     }
441
442     jmethodID jobjectArray_getAccessibleMethodsjintID = curEnv->GetStaticMethodID(cls, methodName, "(I)[Ljava/lang/String;");
443     if (jobjectArray_getAccessibleMethodsjintID == NULL)
444     {
445         throw GiwsException::JniMethodNotFoundException(curEnv, methodName);
446     }
447
448     jobjectArray res = static_cast<jobjectArray>(curEnv->CallStaticObjectMethod(cls, jobjectArray_getAccessibleMethodsjintID, id));
449     if (curEnv->ExceptionCheck())
450     {
451         throw GiwsException::JniCallMethodException(curEnv);
452     }
453     jint lenRow = curEnv->GetArrayLength(res);
454     jboolean isCopy = JNI_FALSE;
455
456     char **addr = new char*[lenRow];
457     jstring *resString = new jstring[lenRow];
458
459     for (jsize i = 0; i < lenRow; i++)
460     {
461         resString[i] = reinterpret_cast<jstring>(curEnv->GetObjectArrayElement(res, i));
462         addr[i] = const_cast<char *>(curEnv->GetStringUTFChars(resString[i], &isCopy));
463     }
464     int lenCol = lenRow == 0 ? 0 : 1;
465     allocator.allocate(lenRow, lenCol, addr);
466     /*
467             SciErr err = createMatrixOfString(pvApiCtx, pos, lenCol, lenRow, addr);
468
469             for (jsize i = 0; i < lenRow; i++)
470             {
471                 curEnv->ReleaseStringUTFChars(resString[i], addr[i]);
472                 curEnv->DeleteLocalRef(resString[i]);
473                 }*/
474     delete[] addr;
475     delete[] resString;
476
477     // if (err.iErr)
478     // {
479     //     throw org_scilab_modules_external_objects_java::NoMoreScilabMemoryException();
480     // }
481
482     curEnv->DeleteLocalRef(res);
483     curEnv->DeleteLocalRef(cls);
484     if (curEnv->ExceptionCheck())
485     {
486         throw GiwsException::JniCallMethodException(curEnv);
487     }
488 };
489 }