JIMS: can now compile a set of Java files
[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     JavaVM *vm = getScilabJavaVM();
386     const int ret = ScilabJavaCompiler::compileCode(vm, className, code, size);
387
388     if (ret != 0 && ret != -1)
389     {
390         ScilabAutoCleaner::registerVariable(envId, ret);
391     }
392
393     return ret;
394 }
395
396 void ScilabJavaEnvironment::enabletrace(const char * filename)
397 {
398     JavaVM *vm = getScilabJavaVM();
399     ScilabJavaObject::enableTrace(vm, filename);
400     traceEnabled = true;
401 }
402
403 void ScilabJavaEnvironment::disabletrace(void)
404 {
405     JavaVM *vm = getScilabJavaVM();
406     ScilabJavaObject::disableTrace(vm);
407     traceEnabled = false;
408 }
409
410 void ScilabJavaEnvironment::writeLog(const std::string & fun, const std::string str, ...) const
411 {
412     if (traceEnabled)
413     {
414         JavaVM * vm = getScilabJavaVM();
415         char _str[LOG_BUFFER_SIZE];
416         va_list args;
417
418         va_start(args, str);
419         vsnprintf(_str, LOG_BUFFER_SIZE, str.c_str(), args);
420         va_end(args);
421
422         ScilabJavaObject::writeLog(vm, _str);
423     }
424 }
425
426 #define SCILABJAVAOBJECT "org/scilab/modules/external_objects_java/ScilabJavaObject"
427
428 void ScilabJavaEnvironment::getMethodResult(JavaVM * jvm_, const char * const methodName, int id, const ScilabStringStackAllocator & allocator)
429 {
430     JNIEnv * curEnv = NULL;
431     jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
432     jclass cls = curEnv->FindClass(SCILABJAVAOBJECT);
433     if (cls == NULL)
434     {
435         throw GiwsException::JniClassNotFoundException(curEnv, SCILABJAVAOBJECT);
436     }
437
438     jmethodID jobjectArray_getAccessibleMethodsjintID = curEnv->GetStaticMethodID(cls, methodName, "(I)[Ljava/lang/String;");
439     if (jobjectArray_getAccessibleMethodsjintID == NULL)
440     {
441         throw GiwsException::JniMethodNotFoundException(curEnv, methodName);
442     }
443
444     jobjectArray res = static_cast<jobjectArray>(curEnv->CallStaticObjectMethod(cls, jobjectArray_getAccessibleMethodsjintID, id));
445     if (curEnv->ExceptionCheck())
446     {
447         throw GiwsException::JniCallMethodException(curEnv);
448     }
449     jint lenRow = curEnv->GetArrayLength(res);
450     jboolean isCopy = JNI_FALSE;
451
452     char **addr = new char*[lenRow];
453     jstring *resString = new jstring[lenRow];
454
455     for (jsize i = 0; i < lenRow; i++)
456     {
457         resString[i] = reinterpret_cast<jstring>(curEnv->GetObjectArrayElement(res, i));
458         addr[i] = const_cast<char *>(curEnv->GetStringUTFChars(resString[i], &isCopy));
459     }
460     int lenCol = lenRow == 0 ? 0 : 1;
461     allocator.allocate(lenRow, lenCol, addr);
462     /*
463             SciErr err = createMatrixOfString(pvApiCtx, pos, lenCol, lenRow, addr);
464
465             for (jsize i = 0; i < lenRow; i++)
466             {
467                 curEnv->ReleaseStringUTFChars(resString[i], addr[i]);
468                 curEnv->DeleteLocalRef(resString[i]);
469                 }*/
470     delete[] addr;
471     delete[] resString;
472
473     // if (err.iErr)
474     // {
475     //     throw org_scilab_modules_external_objects_java::NoMoreScilabMemoryException();
476     // }
477
478     curEnv->DeleteLocalRef(res);
479     curEnv->DeleteLocalRef(cls);
480     if (curEnv->ExceptionCheck())
481     {
482         throw GiwsException::JniCallMethodException(curEnv);
483     }
484 };
485 }