EO: insert/extract 'list()' and '$+1' is now handled
[scilab.git] / scilab / modules / external_objects_java / src / java / org / scilab / modules / external_objects_java / ScilabJavaObject.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - 2011 - Calixte DENIZET <calixte@contrib.scilab.org>
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.1-en.txt
10  *
11  */
12
13 package org.scilab.modules.external_objects_java;
14
15 import java.beans.BeanInfo;
16 import java.beans.IntrospectionException;
17 import java.beans.Introspector;
18 import java.beans.MethodDescriptor;
19 import java.beans.PropertyDescriptor;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.PrintStream;
23 import java.lang.reflect.Array;
24 import java.lang.reflect.Field;
25 import java.lang.reflect.InvocationTargetException;
26 import java.lang.reflect.Method;
27 import java.lang.reflect.Modifier;
28 import java.nio.Buffer;
29 import java.nio.ByteBuffer;
30 import java.nio.ByteOrder;
31 import java.nio.CharBuffer;
32 import java.nio.DoubleBuffer;
33 import java.nio.FloatBuffer;
34 import java.nio.IntBuffer;
35 import java.nio.LongBuffer;
36 import java.nio.ShortBuffer;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.HashMap;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.TreeSet;
44 import java.util.logging.FileHandler;
45 import java.util.logging.Level;
46 import java.util.logging.Logger;
47 import java.util.logging.SimpleFormatter;
48
49 /**
50  * Main class to communicate with Scilab via jni interface generated with Giws.
51  * @autor Calixte DENIZET
52  */
53 @SuppressWarnings(value = {"unchecked", "serial"})
54 public class ScilabJavaObject {
55
56     private static final int INITIALCAPACITY = 1024;
57     private static final Map<Class, Integer> unwrappableType = new HashMap<Class, Integer>(51);
58     private static final Map<Class, Integer> listBaseType = new HashMap<Class, Integer>(9);
59     private static final Class[] returnType = new Class[1];
60
61     static final Map<Class, Class> primTypes = new HashMap<Class, Class>(8);
62
63     private static int currentPos = 1;
64     private static FreePlace freePlace = new FreePlace();
65
66     static boolean debug;
67     static Logger logger;
68     static FileHandler handler;
69
70     protected static int currentCapacity = INITIALCAPACITY;
71     protected static ScilabJavaObject[] arraySJO = new ScilabJavaObject[currentCapacity];
72
73     private static final class Poly {
74         private final double[] coefs;
75         public Poly(double[] coefs) {
76             this.coefs = coefs;
77         }
78     };
79
80     static {
81         primTypes.put(double.class, Double.class);
82         primTypes.put(float.class, Float.class);
83         primTypes.put(int.class, Integer.class);
84         primTypes.put(short.class, Short.class);
85         primTypes.put(byte.class, Byte.class);
86         primTypes.put(char.class, Character.class);
87         primTypes.put(long.class, Long.class);
88         primTypes.put(boolean.class, Boolean.class);
89
90         unwrappableType.put(double.class, 2);
91         unwrappableType.put(double[].class, 3);
92         unwrappableType.put(double[][].class, 4);
93         unwrappableType.put(String.class, 5);
94         unwrappableType.put(String[].class, 6);
95         unwrappableType.put(String[][].class, 7);
96         unwrappableType.put(boolean.class, 8);
97         unwrappableType.put(boolean[].class, 9);
98         unwrappableType.put(boolean[][].class, 10);
99         unwrappableType.put(byte.class, 11);
100         unwrappableType.put(byte[].class, 12);
101         unwrappableType.put(byte[][].class, 13);
102         unwrappableType.put(short.class, 17);
103         unwrappableType.put(short[].class, 18);
104         unwrappableType.put(short[][].class, 19);
105         unwrappableType.put(char.class, 20);
106         unwrappableType.put(char[].class, 21);
107         unwrappableType.put(char[][].class, 22);
108         unwrappableType.put(int.class, 23);
109         unwrappableType.put(int[].class, 24);
110         unwrappableType.put(int[][].class, 25);
111         unwrappableType.put(long.class, 29);
112         unwrappableType.put(long[].class, 30);
113         unwrappableType.put(long[][].class, 31);
114         unwrappableType.put(float.class, 35);
115         unwrappableType.put(float[].class, 36);
116         unwrappableType.put(float[][].class, 37);
117         unwrappableType.put(Double.class, 2);
118         unwrappableType.put(Double[].class, 3);
119         unwrappableType.put(Double[][].class, 4);
120         unwrappableType.put(Integer.class, 23);
121         unwrappableType.put(Integer[].class, 24);
122         unwrappableType.put(Integer[][].class, 25);
123         unwrappableType.put(Long.class, 29);
124         unwrappableType.put(Long[].class, 30);
125         unwrappableType.put(Long[][].class, 31);
126         unwrappableType.put(Byte.class, 11);
127         unwrappableType.put(Byte[].class, 12);
128         unwrappableType.put(Byte[][].class, 13);
129         unwrappableType.put(Character.class, 20);
130         unwrappableType.put(Character[].class, 21);
131         unwrappableType.put(Character[][].class, 22);
132         unwrappableType.put(Boolean.class, 8);
133         unwrappableType.put(Boolean[].class, 9);
134         unwrappableType.put(Boolean[][].class, 10);
135         unwrappableType.put(Float.class, 35);
136         unwrappableType.put(Float[].class, 36);
137         unwrappableType.put(Float[][].class, 37);
138         unwrappableType.put(Short.class, 17);
139         unwrappableType.put(Short[].class, 18);
140         unwrappableType.put(Short[][].class, 19);
141
142         listBaseType.put(Double.class, 3);
143         listBaseType.put(Integer.class, 24);
144         listBaseType.put(Long.class, 30);
145         listBaseType.put(Byte.class, 12);
146         listBaseType.put(Character.class, 21);
147         listBaseType.put(Boolean.class, 9);
148         listBaseType.put(Float.class, 36);
149         listBaseType.put(Short.class, 18);
150         listBaseType.put(String.class, 6);
151
152         arraySJO[0] = new ScilabJavaObject(null, null);
153     }
154
155     protected Object object;
156     protected Class clazz;
157     protected int id;
158
159     /**
160      * Constructor
161      * @param obj the Java Object to wrap
162      */
163     public ScilabJavaObject(Object obj) {
164         this(obj, obj == null ? null : obj.getClass());
165     }
166
167     /**
168      * Constructor
169      * @param obj the Java Object to wrap
170      * @param clazz the Java Object class
171      */
172     public ScilabJavaObject(Object obj, Class clazz) {
173         this.object = obj;
174         this.clazz = clazz;
175
176         if (obj != null) {
177             int fp = freePlace.getFreePlace();
178             if (fp == -1) {
179                 this.id = currentPos;
180                 ++currentPos;
181             } else {
182                 this.id = fp;
183             }
184
185             arraySJO[this.id] = this;
186
187             if (debug) {
188                 logger.log(Level.INFO, "Object creation with id=" + this.id + " and class=" + clazz.toString());
189             }
190
191             if (currentPos >= currentCapacity) {
192                 currentCapacity = currentCapacity * 2;
193                 ScilabJavaObject[] arr = new ScilabJavaObject[currentCapacity];
194                 System.arraycopy(arraySJO, 0, arr, 0, currentPos);
195                 arraySJO = arr;
196                 if (debug) {
197                     logger.log(Level.INFO, "Scope copy");
198                 }
199             }
200         } else {
201             if (debug) {
202                 logger.log(Level.INFO, "Object creation with id=0");
203             }
204             this.id = 0;
205         }
206     }
207
208     /**
209      * Do nothing !
210      */
211     public static final void initScilabJavaObject() { }
212
213     /**
214      * @param filename the log file
215      */
216     public static final void enableTrace(String filename) throws ScilabJavaException {
217         if (debug) {
218             disableTrace();
219         }
220
221         debug = true;
222         logger = Logger.getLogger("JIMS");
223
224         try {
225             handler = new FileHandler(filename, true);
226             logger.addHandler(handler);
227             logger.setLevel(Level.ALL);
228             SimpleFormatter formatter = new SimpleFormatter();
229             handler.setFormatter(formatter);
230         } catch (SecurityException e) {
231             debug = false;
232             throw new ScilabJavaException("A security exception has been thrown:\n" + e);
233         } catch (IOException e) {
234             debug = false;
235             throw new ScilabJavaException("I/O problem:\n" + e);
236         }
237     }
238
239     public static final void writeLog(String s) {
240         if (debug) {
241             logger.log(Level.INFO, s);
242         }
243     }
244
245     /**
246      * Disable trace
247      */
248     public static final void disableTrace() {
249         if (debug && logger != null && handler != null) {
250             logger.removeHandler(handler);
251             handler.flush();
252             handler.close();
253             handler = null;
254             debug = false;
255         }
256     }
257
258     /**
259      * {@inheritedDoc}
260      */
261     public String toString() {
262         if (object == null) {
263             return "null";
264         }
265
266         String str = object.toString();
267         if (str != null) {
268             return str;
269         }
270
271         return "Instance of " + object.getClass() + " with hashcode " + System.identityHashCode(object);
272     }
273
274     /**
275      * Create a new identical reference to a java object
276      * @return A deep copy of this {@link ScilabJavaObject}
277      */
278     @Override
279     protected ScilabJavaObject clone() {
280         return new ScilabJavaObject(object, clazz);
281     }
282
283     /**
284      * Get info as returned by java -version
285      * @return version
286      */
287     public static final String[] getInfos() {
288         try {
289             Class c = Class.forName("sun.misc.Version");
290             Method m = c.getMethod("print", new Class[] { PrintStream.class });
291             ByteArrayOutputStream baos = new ByteArrayOutputStream();
292             PrintStream out = new PrintStream(baos);
293             m.invoke(null, out);
294             out.flush();
295             String[] ret = baos.toString().split("\n");
296             out.close();
297             baos.close();
298
299             return ret;
300         } catch (Exception e) {
301             return null;
302         }
303     }
304
305     /**
306      * @param id the Java Object id
307      * @return the string to represent this object
308      */
309     public static final String getRepresentation(final int id) {
310         if (arraySJO[id] != null) {
311             return arraySJO[id].toString();
312         }
313
314         return "Invalid Java object";
315     }
316
317     /**
318      * @param id the Java Object id
319      * @return true if the object is valid
320      */
321     public static final boolean isValidJavaObject(final int id) {
322         return id == 0 || (id > 0 && arraySJO[id] != null);
323     }
324
325     /**
326      * @param id the Java Object id
327      * @param index an array of index
328      * @return the id of the element at position given by index in id
329      */
330     public static final int getArrayElement(final int id, final int[] index) throws ScilabJavaException {
331         if (id > 0) {
332             if (debug) {
333                 StringBuffer buf = new StringBuffer();
334                 buf.append("(");
335                 if (index.length > 0) {
336                     int i = 0;
337                     for (; i < index.length - 1; i++) {
338                         buf.append(Integer.toString(index[i]));
339                         buf.append(",");
340                     }
341                     buf.append(Integer.toString(index[i]));
342                 }
343                 buf.append(")");
344                 logger.log(Level.INFO, "Get array element: array id=" + id + " at position " + buf.toString());
345             }
346
347             if (arraySJO[id] == null) {
348                 throw new ScilabJavaException("Invalid Java object");
349             }
350
351             return new ScilabJavaObject(ScilabJavaArray.get(arraySJO[id].object, index)).id;
352         }
353         throw new ScilabJavaException("null is not an array");
354     }
355
356     /**
357      * @param id the Java Object id
358      * @param index an array of index
359      * @param idArg the id of an element to put at the position given by index
360      */
361     public static final void setArrayElement(final int id, final int[] index, final int idArg) throws ScilabJavaException {
362         if (id > 0) {
363             if (debug) {
364                 StringBuffer buf = new StringBuffer();
365                 buf.append("(");
366                 if (index.length > 0) {
367                     int i = 0;
368                     for (; i < index.length - 1; i++) {
369                         buf.append(Integer.toString(index[i]));
370                         buf.append(",");
371                     }
372                     buf.append(Integer.toString(index[i]));
373                 }
374                 buf.append(")");
375                 logger.log(Level.INFO, "Set array element: array id=" + id + " at position " + buf.toString() + " and element id=" + idArg);
376             }
377
378             if (arraySJO[id] == null) {
379                 throw new ScilabJavaException("Invalid Java object");
380             }
381
382             ScilabJavaArray.set(arraySJO[id].object, index, arraySJO[idArg].object);
383         } else {
384             throw new ScilabJavaException("null is not an array");
385         }
386     }
387
388     /**
389      * @param id the Java Object id
390      * @return the accessibles methods and fields corresponding to the given path
391      */
392     public static final String[] getCompletion(final int id, final String[] fieldPath) throws ScilabJavaException {
393         if (id > 0) {
394             if (debug) {
395                 logger.log(Level.INFO, "Get accessible methods and fields in object id=" + id + " with path " + Arrays.deepToString(fieldPath));
396             }
397
398             if (arraySJO[id] == null) {
399                 throw new ScilabJavaException("Invalid Java object");
400             }
401
402             Class clazz = arraySJO[id].clazz;
403             final boolean isClass = arraySJO[id].object == clazz;
404
405             if (fieldPath.length == 0) {
406                 return getFieldsAndMethods(clazz, isClass);
407             }
408
409             if (isClass) {
410                 // We have a class object
411                 try {
412                     Field f = clazz.getField(fieldPath[0]);
413                     int modifiers = f.getModifiers();
414                     if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) {
415                         clazz = f.getType();
416                     } else {
417                         return new String[0];
418                     }
419                 } catch (Exception e) {
420                     return new String[0];
421                 }
422             }
423
424             for (int i = (isClass ? 1 : 0); i < fieldPath.length; i++) {
425                 try {
426                     Field f = clazz.getField(fieldPath[i]);
427                     if (Modifier.isPublic(f.getModifiers())) {
428                         clazz = f.getType();
429                     } else {
430                         return new String[0];
431                     }
432                 } catch (Exception e) {
433                     return new String[0];
434                 }
435             }
436
437             return getFieldsAndMethods(clazz, false);
438         } else {
439             return new String[0];
440         }
441     }
442
443     /**
444      * Get fields and methods in a Class
445      * @param clazz the base class
446      * @return names
447      */
448     private static final String[] getFieldsAndMethods(final Class clazz, final boolean staticOnly) {
449         if (clazz.isArray()) {
450             return new String[] {"length"};
451         }
452
453         try {
454             final Field[] fs = clazz.getFields();
455             final Method[] ms = clazz.getMethods();
456
457             Set<String> set = new TreeSet<String>();
458             for (Field f : fs) {
459                 final int modifiers = f.getModifiers();
460                 if (Modifier.isPublic(modifiers) && (!staticOnly || Modifier.isStatic(modifiers))) {
461                     set.add(f.getName());
462                 }
463             }
464
465             for (Method m : ms) {
466                 final int modifiers = m.getModifiers();
467                 if (Modifier.isPublic(modifiers) && (!staticOnly || Modifier.isStatic(modifiers))) {
468                     set.add(m.getName());
469                 }
470             }
471
472             // Append beans properties (and remove accessor methods)
473             try {
474                 final BeanInfo info = Introspector.getBeanInfo(clazz);
475
476                 final PropertyDescriptor[] properties = info.getPropertyDescriptors();
477                 if (properties != null) {
478                     for (PropertyDescriptor p : properties) {
479                         set.add(p.getName());
480
481                         final Method getter = p.getReadMethod();
482                         final Method setter = p.getWriteMethod();
483                         if (getter != null) {
484                             set.remove(getter.getName());
485                         }
486                         if (setter != null) {
487                             set.remove(setter.getName());
488                         }
489                     }
490                 }
491             } catch (IntrospectionException e) {
492             }
493
494             return set.toArray(new String[set.size()]);
495         } catch (Exception e) {
496             return new String[0];
497         }
498     }
499
500     /**
501      * @param id the Java Object id
502      * @return the accessibles methods in the object represented by id
503      */
504     public static final String[] getAccessibleMethods(final int id) throws ScilabJavaException {
505         if (id > 0) {
506             if (debug) {
507                 logger.log(Level.INFO, "Get accessible methods in object id=" + id);
508             }
509
510             if (arraySJO[id] == null) {
511                 throw new ScilabJavaException("Invalid Java object");
512             }
513
514             final Method[] ms = arraySJO[id].clazz.getMethods();
515             Set<String> set = new TreeSet<String>();
516             for (Method m : ms) {
517                 if (Modifier.isPublic(m.getModifiers())) {
518                     set.add(m.getName());
519                 }
520             }
521
522             return set.toArray(new String[set.size()]);
523         } else {
524             return new String[0];
525         }
526     }
527
528     /**
529      * @param id the Java Object id
530      * @return the accessibles fields in the object represented by id
531      */
532     public static final String[] getAccessibleFields(final int id) throws ScilabJavaException {
533         if (id > 0) {
534             if (debug) {
535                 logger.log(Level.INFO, "Get accessible fields in object id=" + id);
536             }
537
538             if (arraySJO[id] == null) {
539                 throw new ScilabJavaException("Invalid Java object");
540             }
541
542             if (arraySJO[id].clazz.isArray()) {
543                 return new String[] {"length"};
544             }
545
546             final Field[] f = arraySJO[id].clazz.getFields();
547             final String[] sf = new String[f.length];
548             for (int i = 0; i < f.length; i++) {
549                 if (Modifier.isPublic(f[i].getModifiers())) {
550                     sf[i] = f[i].getName();
551                 }
552             }
553             return sf;
554         } else {
555             return new String[0];
556         }
557     }
558
559     /**
560      * @param id the Java Object id
561      * @return the class name of the object represented by id
562      */
563     public static final String getClassName(final int id) throws ScilabJavaException {
564         if (id > 0) {
565             if (debug) {
566                 logger.log(Level.INFO, "Get class name of object id=" + id);
567             }
568
569             if (arraySJO[id] == null) {
570                 throw new ScilabJavaException("Invalid Java object");
571             }
572
573             return arraySJO[id].clazz.getName();
574         } else {
575             return "null";
576         }
577     }
578
579     /**
580      * @param id the Java Object id
581      * @param fieldName the field name to set
582      * @param idArg the id of the element to set
583      */
584     public static final void setField(final int id, final String fieldName, final int idarg) throws ScilabJavaException {
585         if (id > 0) {
586             Field f = null;
587             try {
588                 if (debug) {
589                     logger.log(Level.INFO, "Set field \'" + fieldName + "\' in object id=" + id + " with value id=" + idarg);
590                 }
591
592                 if (arraySJO[id] == null) {
593                     throw new ScilabJavaException("Invalid Java object");
594                 }
595
596                 try  {
597                     f = arraySJO[id].clazz.getField(fieldName);
598
599                     // standard field access
600                     try {
601                         f.set(arraySJO[id].object, arraySJO[idarg].object);
602                     } catch (IllegalArgumentException e) {
603                         if (f != null && f.getType() == int.class && (arraySJO[idarg].clazz == double.class || arraySJO[idarg].clazz == Double.class) && ((Double) arraySJO[idarg].object).intValue() == ((Double) arraySJO[idarg].object).doubleValue()) {
604                             f.set(arraySJO[id].object, ((Double) arraySJO[idarg].object).intValue());
605                             return;
606                         } else {
607                             throw e;
608                         }
609                     }
610                 } catch (NoSuchFieldException e) {
611                 }
612
613                 // lookup for a bean property
614                 final PropertyDescriptor p = lookupBeanProperty(id, fieldName);
615                 final Method method  = p.getWriteMethod();
616                 if (method == null) {
617                     throw new ScilabJavaException("Cannot read the property " + fieldName + " in object " + getClassName(id));
618                 }
619                 method.invoke(arraySJO[id].object, arraySJO[idarg].object);
620             } catch (IllegalArgumentException e) {
621                 throw new ScilabJavaException("Bad argument value for field " + fieldName + " in object " + getClassName(id));
622             } catch (IllegalAccessException e) {
623                 throw new ScilabJavaException("Cannot access to the field " + fieldName + " in object " + getClassName(id));
624             } catch (InvocationTargetException e) {
625                 throw new ScilabJavaException("Exception occurs on write access to the property " + fieldName + " in object " + getClassName(id));
626             }
627         } else {
628             throw new ScilabJavaException("null is not an object");
629         }
630     }
631
632     /**
633      * @param id the Java Object id
634      * @param fieldName the field name to set
635      * @return the id of the got object
636      */
637     public static final int getField(final int id, final String fieldName) throws ScilabJavaException {
638         if (id > 0) {
639             try {
640                 if (debug) {
641                     logger.log(Level.INFO, "Get field \'" + fieldName + "\' in object id=" + id);
642                 }
643
644                 if (arraySJO[id] == null) {
645                     throw new ScilabJavaException("Invalid Java object");
646                 }
647
648                 if (arraySJO[id].clazz.isArray() && fieldName.equals("length")) {
649                     return new ScilabJavaObject(Array.getLength(arraySJO[id].object), int.class).id;
650                 }
651
652                 if (arraySJO[id].object == arraySJO[id].clazz && fieldName.equals("class")) {
653                     return new ScilabJavaObject(arraySJO[id].object, arraySJO[id].object.getClass()).id;
654                 }
655
656                 try {
657                     final Field f = arraySJO[id].clazz.getField(fieldName);
658                     final Class cl = f.getType();
659                     if (cl == int.class) {
660                         return new ScilabJavaObject(f.getInt(arraySJO[id].object), int.class).id;
661                     } else if (cl == double.class) {
662                         return new ScilabJavaObject(f.getDouble(arraySJO[id].object), double.class).id;
663                     } else if (cl == boolean.class) {
664                         return new ScilabJavaObject(f.getBoolean(arraySJO[id].object), boolean.class).id;
665                     } else if (cl == short.class) {
666                         return new ScilabJavaObject(f.getShort(arraySJO[id].object), short.class).id;
667                     } else if (cl == char.class) {
668                         return new ScilabJavaObject(f.getChar(arraySJO[id].object), char.class).id;
669                     } else if (cl == float.class) {
670                         return new ScilabJavaObject(f.getFloat(arraySJO[id].object), float.class).id;
671                     } else if (cl == byte.class) {
672                         return new ScilabJavaObject(f.getByte(arraySJO[id].object), byte.class).id;
673                     } else if (cl == long.class) {
674                         return new ScilabJavaObject(f.getLong(arraySJO[id].object), long.class).id;
675                     }
676
677                     return new ScilabJavaObject(f.get(arraySJO[id].object)).id;
678                 } catch (NoSuchFieldException e) {
679                 }
680
681                 // lookup for a bean property
682                 final PropertyDescriptor p = lookupBeanProperty(id, fieldName);
683                 final Method method  = p.getReadMethod();
684                 if (method == null) {
685                     throw new ScilabJavaException("Cannot read the field or property " + fieldName + " in object " + getClassName(id));
686                 }
687                 final Object retValue = method.invoke(arraySJO[id].object);
688                 if (retValue == null) {
689                     return new ScilabJavaObject(retValue).id;
690                 }
691
692                 final Class cl = retValue.getClass();
693                 if (cl == int.class) {
694                     return new ScilabJavaObject(retValue, int.class).id;
695                 } else if (cl == double.class) {
696                     return new ScilabJavaObject(retValue, double.class).id;
697                 } else if (cl == boolean.class) {
698                     return new ScilabJavaObject(retValue, boolean.class).id;
699                 } else if (cl == short.class) {
700                     return new ScilabJavaObject(retValue, short.class).id;
701                 } else if (cl == char.class) {
702                     return new ScilabJavaObject(retValue, char.class).id;
703                 } else if (cl == float.class) {
704                     return new ScilabJavaObject(retValue, float.class).id;
705                 } else if (cl == byte.class) {
706                     return new ScilabJavaObject(retValue, byte.class).id;
707                 } else if (cl == long.class) {
708                     return new ScilabJavaObject(retValue, long.class).id;
709                 }
710                 return new ScilabJavaObject(retValue).id;
711             } catch (IllegalArgumentException e) {
712                 throw new ScilabJavaException("Bad argument value for field " + fieldName + " in object " + getClassName(id));
713             } catch (IllegalAccessException e) {
714                 throw new ScilabJavaException("Cannot access to the field " + fieldName + " in object " + getClassName(id));
715             } catch (InvocationTargetException e) {
716                 throw new ScilabJavaException("Exception occurs on read access to the property " + fieldName + " in object " + getClassName(id));
717             }
718         } else {
719             throw new ScilabJavaException("null is not an object");
720         }
721     }
722
723     /**
724      * @param id the Java Object id
725      * @param fieldName the field name to set
726      * @return the type of the field in object represented by id:
727      *         * -1 for unknown
728      *         * 0 for a method
729      *         * 1 for a field
730      */
731     public static final int getFieldType(final int id, final String fieldName) {
732         if (id > 0 && arraySJO[id] != null) {
733             if (debug) {
734                 logger.log(Level.INFO, "Get field type of \'" + fieldName + "\' in object id=" + id);
735             }
736
737             if (isValidMethod(id, fieldName)) {
738                 return 0;
739             }
740             try {
741                 if (arraySJO[id].clazz.isArray()) {
742                     if (fieldName.equals("length")) {
743                         return 1;
744                     } else {
745                         return -1;
746                     }
747                 }
748
749                 if (arraySJO[id].object == arraySJO[id].clazz && fieldName.equals("class")) {
750                     return 1;
751                 }
752
753                 try {
754                     Field f = arraySJO[id].clazz.getField(fieldName);
755                     return 1;
756                 } catch (NoSuchFieldException e) {
757                 }
758
759                 // lookup for a bean property
760                 lookupBeanProperty(id, fieldName);
761                 return 1;
762             } catch (IllegalArgumentException e) {
763                 return -1;
764             } catch (ScilabJavaException e) {
765                 return -1;
766             }
767         }
768
769         return -1;
770     }
771
772     private static final boolean isValidMethod(int id, String methName) {
773         final BeanInfo info;
774         try {
775             info = Introspector.getBeanInfo(arraySJO[id].clazz);
776         } catch (IntrospectionException e) {
777             return false;
778         }
779
780         final MethodDescriptor[] methods = info.getMethodDescriptors();
781         if (methods == null) {
782             return false;
783         }
784
785         for (MethodDescriptor m : methods) {
786             if (methName.equals(m.getName())) {
787                 return true;
788             }
789         }
790
791         return false;
792     }
793
794     private static final PropertyDescriptor lookupBeanProperty(int id, String fieldName) throws ScilabJavaException {
795         final BeanInfo info;
796         try {
797             info = Introspector.getBeanInfo(arraySJO[id].clazz);
798         } catch (IntrospectionException e) {
799             throw new ScilabJavaException("Unable to get properties of object " + getClassName(id));
800         }
801
802         final PropertyDescriptor[] properties = info.getPropertyDescriptors();
803         if (properties == null) {
804             throw new ScilabJavaException("No property " + fieldName + " in object " + getClassName(id));
805         }
806
807         for (PropertyDescriptor p : properties) {
808             if (fieldName.equals(p.getName())) {
809                 return p;
810             }
811         }
812
813         throw new ScilabJavaException("No property " + fieldName + " in object " + getClassName(id));
814     }
815
816     /**
817      * @param id the Java Object id
818      * @param methName the method name to invoke
819      * @param args an array containing the id of the arguments
820      * @return the id of the invocation result
821      */
822     public static final int invoke(final int id, final String methName, final int[] args) throws ScilabJavaException {
823         if (id > 0) {
824             if (debug) {
825                 StringBuffer buf = new StringBuffer();
826                 buf.append("(");
827                 if (args.length > 0) {
828                     int i = 0;
829                     for (; i < args.length - 1; i++) {
830                         buf.append(Integer.toString(args[i]));
831                         buf.append(",");
832                     }
833                     buf.append(Integer.toString(args[i]));
834                 }
835                 buf.append(")");
836                 logger.log(Level.INFO, "Invoke method \'" + methName + "\' in object id=" + id + " with arguments id=" + buf.toString());
837             }
838
839             if (arraySJO[id] != null) {
840                 Object ret = ScilabJavaMethod.invoke(methName, arraySJO[id].clazz, arraySJO[id].object, returnType, args);
841                 if (ret == null && returnType[0] == Void.TYPE) {
842                     return -1;
843                 } else {
844                     return new ScilabJavaObject(ret, returnType[0]).id;
845                 }
846             } else {
847                 throw new ScilabJavaException("Invalid Java object");
848             }
849         } else {
850             throw new ScilabJavaException("null is not an object");
851         }
852     }
853
854     /**
855      * @param id the Java Object id
856      * @param args an array containing the id of the arguments
857      * @return the id of the invocation result
858      */
859     public static final int extract(final int id, final int[] args) throws ScilabJavaException {
860         if (id > 0) {
861             if (debug) {
862                 StringBuffer buf = new StringBuffer();
863                 buf.append("(");
864                 if (args.length > 0) {
865                     int i = 0;
866                     for (; i < args.length - 1; i++) {
867                         buf.append(Integer.toString(args[i]));
868                         buf.append(",");
869                     }
870                     buf.append(Integer.toString(args[i]));
871                 }
872                 buf.append(")");
873                 logger.log(Level.INFO, "Extract in object id=" + id + " with arguments id=" + buf.toString());
874             }
875
876             for (int i = 0; i < args.length; i++) {
877                 if (args[i] < 0 || arraySJO[args[i]] == null) {
878                     throw new ScilabJavaException("Invalid Java object at position " + i);
879                 }
880             }
881
882             if (arraySJO[id] != null) {
883                 Object o = arraySJO[id].object;
884                 for (int i = 0; i < args.length; i++) {
885                     Object a = args[i] == 0 ? null : arraySJO[args[i]].object;
886                     if (o instanceof Map) {
887                         o = ((Map) o).get(a);
888                     } else if (o instanceof List) {
889                         List l = (List) o;
890                         int pos = -1;
891                         if (a instanceof Double) {
892                             // Scilab index begins at 1
893                             pos = ((Double) a).intValue() - 1;
894                         } else if (a instanceof Integer) {
895                             pos = ((Integer) a).intValue() - 1;
896                         } else if (a instanceof Poly) {
897                             /* this '$' polynomial coefs */
898                             pos = ((int) horner(l.size(), (Poly) a)) - 1;
899                         } else {
900                             pos = l.indexOf(a);
901                         }
902                         if (pos >= 0 || pos < l.size()) {
903                             o = l.get(pos);
904                         } else {
905                             throw new ScilabJavaException("Cannot get object at position " + (i + 1));
906                         }
907                     } else if (o.getClass().isArray()) {
908                         int pos = -1;
909                         if (a instanceof Double) {
910                             pos = ((Double) a).intValue();
911                         } else if (a instanceof Integer) {
912                             pos = ((Integer) a).intValue();
913                         }
914
915                         o = ScilabJavaArray.get(o, new int[] {pos - 1});
916                     } else {
917                         throw new ScilabJavaException("Invalid field " + (a == null ? "null" : a.toString()));
918                     }
919                 }
920
921                 if (o == null) {
922                     return 0;
923                 }
924
925                 return new ScilabJavaObject(o).id;
926             }
927             throw new ScilabJavaException("Invalid Java object");
928         } else {
929             throw new ScilabJavaException("null is not an object");
930         }
931     }
932
933     /**
934      * @param id the Java Object id
935      * @param keys an array containing the id of the arguments
936      * @param value the id of the value
937      */
938     public static final void insert(final int id, final int[] keys, final int value) throws ScilabJavaException {
939         if (id > 0) {
940             if (debug) {
941                 StringBuffer buf = new StringBuffer();
942                 buf.append("(");
943                 if (keys.length > 0) {
944                     int i = 0;
945                     for (; i < keys.length - 1; i++) {
946                         buf.append(Integer.toString(keys[i]));
947                         buf.append(",");
948                     }
949                     buf.append(Integer.toString(keys[i]));
950                 }
951                 buf.append(")");
952                 logger.log(Level.INFO, "Insert in object id=" + id + " with arguments id=" + buf.toString() + " and the value id=" + value);
953             }
954
955             if (arraySJO[id] != null) {
956                 Object o = arraySJO[id].object;
957                 for (int i = 0; i < keys.length - 1; i++) {
958                     Object a = keys[i] == 0 ? null : arraySJO[keys[i]].object;
959                     if (o instanceof Map) {
960                         o = ((Map) o).get(a);
961                     } else if (o instanceof List) {
962                         List l = (List) o;
963                         int pos = -1;
964                         if (a instanceof Double) {
965                             // Scilab index begins at 1
966                             pos = ((Double) a).intValue() - 1;
967                         } else if (a instanceof Integer) {
968                             pos = ((Integer) a).intValue() - 1;
969                         } else {
970                             pos = l.indexOf(a);
971                         }
972                         if (pos >= 0 || pos < l.size()) {
973                             o = l.get(pos);
974                         } else {
975                             throw new ScilabJavaException("Cannot get object at position " + (i + 1));
976                         }
977                     } else if (o.getClass().isArray()) {
978                         int pos = -1;
979                         if (a instanceof Double) {
980                             pos = ((Double) a).intValue();
981                         } else if (a instanceof Integer) {
982                             pos = ((Integer) a).intValue();
983                         }
984
985                         o = ScilabJavaArray.get(o, new int[] {pos - 1});
986                     } else {
987                         throw new ScilabJavaException("Invalid field " + (a == null ? "null" : a.toString()));
988                     }
989                 }
990
991                 if (o == null) {
992                     return;
993                 }
994
995                 int last = keys[keys.length - 1];
996                 Object a = last == 0 ? null : arraySJO[last].object;
997                 if (o instanceof Map) {
998                     ((Map) o).put(a, arraySJO[value].object);
999                 } else if (o instanceof List) {
1000                     List l = (List) o;
1001                     int pos = -1;
1002                     if (a instanceof Double) {
1003                         // Scilab index begins at 1
1004                         pos = ((Double) a).intValue() - 1;
1005                     } else if (a instanceof Integer) {
1006                         pos = ((Integer) a).intValue() - 1;
1007                     } else if (a instanceof Poly) {
1008                         /* this '$' polynomial coefs */
1009                         pos = ((int) horner(l.size(), (Poly) a)) - 1;
1010                     } else {
1011                         pos = l.indexOf(a);
1012                     }
1013
1014                     // the last element should be add-ed instead of set-ed
1015                     if (pos >= 0 && pos < l.size()) {
1016                         l.set(pos, arraySJO[value].object);
1017                     } else if (pos < 0) {
1018                         l.add(0, arraySJO[value].object);
1019                     } else {
1020                         l.add(pos, arraySJO[value].object);
1021                     }
1022                 } else if (o.getClass().isArray()) {
1023                     int pos = -1;
1024                     if (a instanceof Double) {
1025                         pos = ((Double) a).intValue();
1026                     } else if (a instanceof Integer) {
1027                         pos = ((Integer) a).intValue();
1028                     }
1029
1030                     ScilabJavaArray.set(o, new int[] {pos - 1}, arraySJO[value].object);
1031                 } else {
1032                     throw new ScilabJavaException("Invalid field " + (a == null ? "null" : a.toString()));
1033                 }
1034
1035                 return;
1036             }
1037             throw new ScilabJavaException("Invalid Java object");
1038         } else {
1039             throw new ScilabJavaException("null is not an object");
1040         }
1041     }
1042
1043     /**
1044      * Compute expected index using the coefs dans the actual size
1045      *
1046      * @param size the x value
1047      * @param coefs the a_n values
1048      * @see http://en.wikipedia.org/wiki/Horner's_method
1049      */
1050     private static final double horner(double size, Poly p) {
1051         double result = 0;
1052         for (int i = p.coefs.length - 1; i >= 0; i--) {
1053             result = result * size + p.coefs[i];
1054         }
1055         return result;
1056     }
1057
1058     /**
1059      * @param id the Java Object id
1060      * @param className the target class name
1061      * @return the id of the cast result
1062      */
1063     public static final int javaCast(final int id, final String className) throws ScilabJavaException {
1064         if (id > 0) {
1065             if (debug) {
1066                 logger.log(Level.INFO, "Cast object id=" + id + " to class " + className);
1067             }
1068
1069             final int idC = ScilabClassLoader.loadJavaClass(className, false);
1070             final Class clazz = (Class) arraySJO[idC].object;
1071             try {
1072                 int idR = new ScilabJavaObject(clazz.cast(arraySJO[id].object), clazz).id;
1073                 removeScilabJavaObject(idC);
1074                 return idR;
1075             } catch (ClassCastException e) {
1076                 throw new ScilabJavaException("Cannot cast object " + getClassName(id) + " into " + getClassName(idC));
1077             }
1078         } else {
1079             throw new ScilabJavaException("null is not an object");
1080         }
1081     }
1082
1083     /**
1084      * @param id the Java Object id
1085      * @param classId the target class id
1086      * @return the id of the cast result
1087      */
1088     public static final int javaCast(final int id, final int classId) throws ScilabJavaException {
1089         if (id > 0) {
1090             if (debug) {
1091                 logger.log(Level.INFO, "Cast object id=" + id + " to class with id=" + classId);
1092             }
1093
1094             final Class clazz = (Class) arraySJO[classId].object;
1095             try {
1096                 return new ScilabJavaObject(clazz.cast(arraySJO[id].object), clazz).id;
1097             } catch (ClassCastException e) {
1098                 throw new ScilabJavaException("Cannot cast object " + getClassName(id) + " into " + getClassName(classId));
1099             }
1100         } else {
1101             throw new ScilabJavaException("null is not an object");
1102         }
1103     }
1104
1105     /**
1106      * Remove an object.
1107      * @param id the Java Object id
1108      */
1109     public static final void removeScilabJavaObject(final int id) {
1110         if (id > 0 && arraySJO[id] != null) {
1111             if (debug) {
1112                 logger.log(Level.INFO, "Remove object id=" + id);
1113             }
1114             freePlace.addFreePlace(id);
1115             if (arraySJO[id] instanceof ScilabJavaClass) {
1116                 ScilabClassLoader.removeID(id);
1117             }
1118             arraySJO[id] = null;
1119         }
1120     }
1121
1122     /**
1123      * Remove objects.
1124      * @param ids the Java Object ids
1125      */
1126     public static final void removeScilabJavaObject(final int[] ids) {
1127         for (int id : ids) {
1128             removeScilabJavaObject(id);
1129         }
1130     }
1131
1132     /**
1133      * Set the limit of a direct buffer to 0 to make it unusable.
1134      * @param id the Java Object id
1135      */
1136     public static final void limitDirectBuffer(final int id) {
1137         if (id > 0 && arraySJO[id] != null && (arraySJO[id].object instanceof Buffer)) {
1138             if (debug) {
1139                 logger.log(Level.INFO, "Limit direct buffer with id=" + id);
1140             }
1141
1142             ((Buffer) arraySJO[id].object).limit(0);
1143         }
1144     }
1145
1146     /**
1147      * Remove all the objects and start a garbage collection
1148      */
1149     public static final void garbageCollect() {
1150         if (debug) {
1151             logger.log(Level.INFO, "Garbage collection");
1152         }
1153         currentPos = 1;
1154         currentCapacity = INITIALCAPACITY;
1155         arraySJO = new ScilabJavaObject[currentCapacity];
1156         arraySJO[0] = new ScilabJavaObject(null, null);
1157         freePlace = new FreePlace();
1158         ScilabClassLoader.clazz.clear();
1159         System.gc();
1160     }
1161
1162     /**
1163      * @param x the variable to wrap into a Java Object
1164      * @return the corresponding id
1165      */
1166     public static final int wrapAsDirectByteBuffer(final ByteBuffer x) {
1167         x.order(ByteOrder.nativeOrder());
1168         return new ScilabJavaObject(x, ByteBuffer.class).id;
1169     }
1170
1171     /**
1172      * @param x the variable to wrap into a Java Object
1173      * @return the corresponding id
1174      */
1175     public static final int wrapAsDirectDoubleBuffer(final ByteBuffer x) {
1176         x.order(ByteOrder.nativeOrder());
1177         return new ScilabJavaObject(x.asDoubleBuffer(), DoubleBuffer.class).id;
1178     }
1179
1180     /**
1181      * @param x the variable to wrap into a Java Object
1182      * @return the corresponding id
1183      */
1184     public static final int wrapAsDirectIntBuffer(final ByteBuffer x) {
1185         x.order(ByteOrder.nativeOrder());
1186         return new ScilabJavaObject(x.asIntBuffer(), IntBuffer.class).id;
1187     }
1188
1189     /**
1190      * @param x the variable to wrap into a Java Object
1191      * @return the corresponding id
1192      */
1193     public static final int wrapAsDirectCharBuffer(final ByteBuffer x) {
1194         x.order(ByteOrder.nativeOrder());
1195         return new ScilabJavaObject(x.asCharBuffer(), CharBuffer.class).id;
1196     }
1197
1198     /**
1199      * @param x the variable to wrap into a Java Object
1200      * @return the corresponding id
1201      */
1202     public static final int wrapAsDirectFloatBuffer(final ByteBuffer x) {
1203         x.order(ByteOrder.nativeOrder());
1204         return new ScilabJavaObject(x.asFloatBuffer(), FloatBuffer.class).id;
1205     }
1206
1207     /**
1208      * @param x the variable to wrap into a Java Object
1209      * @return the corresponding id
1210      */
1211     public static final int wrapAsDirectLongBuffer(final ByteBuffer x) {
1212         x.order(ByteOrder.nativeOrder());
1213         return new ScilabJavaObject(x.asLongBuffer(), LongBuffer.class).id;
1214     }
1215
1216     /**
1217      * @param x the variable to wrap into a Java Object
1218      * @return the corresponding id
1219      */
1220     public static final int wrapAsDirectShortBuffer(final ByteBuffer x) {
1221         x.order(ByteOrder.nativeOrder());
1222         return new ScilabJavaObject(x.asShortBuffer(), ShortBuffer.class).id;
1223     }
1224
1225     /**
1226      * @param x the variable to wrap into a Java Object
1227      * @return the corresponding id
1228      */
1229     public static final int wrap(final double x) {
1230         return new ScilabJavaObject(x, double.class).id;
1231     }
1232
1233     /**
1234      * @param x the variable to wrap into a Java Object
1235      * @return the corresponding id
1236      */
1237     public static final int wrap(final double[] x) {
1238         return new ScilabJavaObject(x, double[].class).id;
1239     }
1240
1241     /**
1242      * @param x the variable to wrap into a Java Object
1243      * @return the corresponding id
1244      */
1245     public static final int wrap(final double[][] x) {
1246         return new ScilabJavaObject(x, double[][].class).id;
1247     }
1248
1249     /**
1250      * @param x the variable to wrap into a Java Object
1251      * @return the corresponding id
1252      */
1253     public static final int wrap(final int x) {
1254         return new ScilabJavaObject(x, int.class).id;
1255     }
1256
1257     /**
1258      * @param x the variable to wrap into a Java Object
1259      * @return the corresponding id
1260      */
1261     public static final int wrap(final int[] x) {
1262         return new ScilabJavaObject(x, int[].class).id;
1263     }
1264
1265     /**
1266      * @param x the variable to wrap into a Java Object
1267      * @return the corresponding id
1268      */
1269     public static final int wrap(final int[][] x) {
1270         return new ScilabJavaObject(x, int[][].class).id;
1271     }
1272
1273     /**
1274      * @param x the variable to wrap into a Java Object
1275      * @return the corresponding id
1276      */
1277     public static final int wrap(final long x) {
1278         return new ScilabJavaObject(x, long.class).id;
1279     }
1280
1281     /**
1282      * @param x the variable to wrap into a Java Object
1283      * @return the corresponding id
1284      */
1285     public static final int wrap(final long[] x) {
1286         return new ScilabJavaObject(x, long[].class).id;
1287     }
1288
1289     /**
1290      * @param x the variable to wrap into a Java Object
1291      * @return the corresponding id
1292      */
1293     public static final int wrap(final long[][] x) {
1294         return new ScilabJavaObject(x, long[][].class).id;
1295     }
1296
1297     /**
1298      * @param x the variable to wrap into a Java Object
1299      * @return the corresponding id
1300      */
1301     public static final int wrap(final byte x) {
1302         return new ScilabJavaObject(x, byte.class).id;
1303     }
1304
1305     /**
1306      * @param x the variable to wrap into a Java Object
1307      * @return the corresponding id
1308      */
1309     public static final int wrap(final byte[] x) {
1310         return new ScilabJavaObject(x, byte[].class).id;
1311     }
1312
1313     /**
1314      * @param x the variable to wrap into a Java Object
1315      * @return the corresponding id
1316      */
1317     public static final int wrap(final byte[][] x) {
1318         return new ScilabJavaObject(x, byte[][].class).id;
1319     }
1320
1321     /**
1322      * @param x the variable to wrap into a Java Object
1323      * @return the corresponding id
1324      */
1325     public static final int wrap(final short x) {
1326         return new ScilabJavaObject(x, short.class).id;
1327     }
1328
1329     /**
1330      * @param x the variable to wrap into a Java Object
1331      * @return the corresponding id
1332      */
1333     public static final int wrap(final short[] x) {
1334         return new ScilabJavaObject(x, short[].class).id;
1335     }
1336
1337     /**
1338      * @param x the variable to wrap into a Java Object
1339      * @return the corresponding id
1340      */
1341     public static final int wrap(final short[][] x) {
1342         return new ScilabJavaObject(x, short[][].class).id;
1343     }
1344
1345     /**
1346      * @param x the variable to wrap into a Java Object
1347      * @return the corresponding id
1348      */
1349     public static final int wrap(final String x) {
1350         return new ScilabJavaObject(x, String.class).id;
1351     }
1352
1353     /**
1354      * @param x the variable to wrap into a Java Object
1355      * @return the corresponding id
1356      */
1357     public static final int wrap(final String[] x) {
1358         return new ScilabJavaObject(x, String[].class).id;
1359     }
1360
1361     /**
1362      * @param x the variable to wrap into a Java Object
1363      * @return the corresponding id
1364      */
1365     public static final int wrap(final String[][] x) {
1366         return new ScilabJavaObject(x, String[][].class).id;
1367     }
1368
1369     /**
1370      * @param x the variable to wrap into a Java Object
1371      * @return the corresponding id
1372      */
1373     public static final int wrap(final boolean x) {
1374         return new ScilabJavaObject(x, boolean.class).id;
1375     }
1376
1377     /**
1378      * @param x the variable to wrap into a Java Object
1379      * @return the corresponding id
1380      */
1381     public static final int wrap(final boolean[] x) {
1382         return new ScilabJavaObject(x, boolean[].class).id;
1383     }
1384
1385     /**
1386      * @param x the variable to wrap into a Java Object
1387      * @return the corresponding id
1388      */
1389     public static final int wrap(final boolean[][] x) {
1390         return new ScilabJavaObject(x, boolean[][].class).id;
1391     }
1392
1393     /**
1394      * @param x the variable to wrap into a Java Object
1395      * @return the corresponding id
1396      */
1397     public static final int wrap(final char x) {
1398         return new ScilabJavaObject(x, char.class).id;
1399     }
1400
1401     /**
1402      * @param x the variable to wrap into a Java Object
1403      * @return the corresponding id
1404      */
1405     public static final int wrap(final char[] x) {
1406         return new ScilabJavaObject(x, char[].class).id;
1407     }
1408
1409     /**
1410      * @param x the variable to wrap into a Java Object
1411      * @return the corresponding id
1412      */
1413     public static final int wrap(final char[][] x) {
1414         return new ScilabJavaObject(x, char[][].class).id;
1415     }
1416
1417     /**
1418      * @param x the variable to wrap into a Java Object
1419      * @return the corresponding id
1420      */
1421     public static final int wrap(final float x) {
1422         return new ScilabJavaObject(x, float.class).id;
1423     }
1424
1425     /**
1426      * @param x the variable to wrap into a Java Object
1427      * @return the corresponding id
1428      */
1429     public static final int wrap(final float[] x) {
1430         return new ScilabJavaObject(x, float[].class).id;
1431     }
1432
1433     /**
1434      * @param x the variable to wrap into a Java Object
1435      * @return the corresponding id
1436      */
1437     public static final int wrap(final float[][] x) {
1438         return new ScilabJavaObject(x, float[][].class).id;
1439     }
1440
1441     /**
1442      * Wrap the ids into a Java collection
1443      *
1444      * The implementation is a raw {@link java.util.ArrayList}.
1445      *
1446      * @param ids the java object to put into
1447      * @return a collection id
1448      */
1449     public static final int wrapList(final int[] ids) {
1450         final ArrayList<Object> list = new ArrayList<Object>(ids.length);
1451         for (int i = 0; i < ids.length; i++) {
1452             list.add(arraySJO[ids[i]]);
1453         }
1454
1455         return new ScilabJavaObject(list, ArrayList.class).id;
1456     }
1457
1458     /**
1459      * Wrap the ids into a Java collection
1460      *
1461      * The implementation is a raw {@link java.util.ArrayList}.
1462      *
1463      * @param ids the java object to put into
1464      * @return a collection id
1465      */
1466     public static final int wrapPoly(final double[] coefs) {
1467         final Poly p = new Poly(coefs);
1468         return new ScilabJavaObject(p, Poly.class).id;
1469     }
1470
1471     /**
1472      * @param id the Java Object id
1473      * @return the resulting unwrapping
1474      */
1475     public static final double unwrapDouble(final int id) {
1476         return ((Double) (arraySJO[id].object)).doubleValue();
1477     }
1478
1479     /**
1480      * @param id the Java Object id
1481      * @return the resulting unwrapping
1482      */
1483     public static final Object unwrapRowDouble(final int id) {
1484         if (arraySJO[id].object instanceof List) {
1485             return ScilabJavaArray.toDoubleArray((List<Double>) arraySJO[id].object);
1486         } else if (arraySJO[id].object instanceof Double[]) {
1487             return ScilabJavaArray.toPrimitive((Double[]) arraySJO[id].object);
1488         } else if (arraySJO[id].object instanceof DoubleBuffer && !((DoubleBuffer) arraySJO[id].object).isDirect()) {
1489             return ((DoubleBuffer) arraySJO[id].object).array();
1490         }
1491
1492         return arraySJO[id].object;
1493     }
1494
1495     /**
1496      * @param id the Java Object id
1497      * @return the resulting unwrapping
1498      */
1499     public static final double[][] unwrapMatDouble(final int id) {
1500         if (arraySJO[id].object instanceof Double[][]) {
1501             Object o = ScilabJavaArray.toPrimitive(arraySJO[id].object);
1502             return (double[][]) ScilabJavaArray.toPrimitive(arraySJO[id].object);
1503         }
1504
1505         return (double[][]) arraySJO[id].object;
1506     }
1507
1508     /**
1509      * @param id the Java Object id
1510      * @return the resulting unwrapping
1511      */
1512     public static final int unwrapInt(final int id) {
1513         return ((Integer) (arraySJO[id].object)).intValue();
1514     }
1515
1516     /**
1517      * @param id the Java Object id
1518      * @return the resulting unwrapping
1519      */
1520     public static final Object unwrapRowInt(final int id) {
1521         if (arraySJO[id].object instanceof List) {
1522             return ScilabJavaArray.toIntArray((List<Integer>) arraySJO[id].object);
1523         } else if (arraySJO[id].object instanceof Integer[]) {
1524             return ScilabJavaArray.toPrimitive((Integer[]) arraySJO[id].object);
1525         } else if (arraySJO[id].object instanceof IntBuffer && !((IntBuffer) arraySJO[id].object).isDirect()) {
1526             return ((IntBuffer) arraySJO[id].object).array();
1527         }
1528
1529         return arraySJO[id].object;
1530     }
1531
1532     /**
1533      * @param id the Java Object id
1534      * @return the resulting unwrapping
1535      */
1536     public static final int[][] unwrapMatInt(final int id) {
1537         if (arraySJO[id].object instanceof Integer[][]) {
1538             return (int[][]) ScilabJavaArray.toPrimitive(arraySJO[id].object);
1539         }
1540
1541         return (int[][]) (arraySJO[id].object);
1542     }
1543
1544     /**
1545      * @param id the Java Object id
1546      * @return the resulting unwrapping
1547      */
1548     public static final short unwrapShort(final int id) {
1549         return ((Short) (arraySJO[id].object)).shortValue();
1550     }
1551
1552     /**
1553      * @param id the Java Object id
1554      * @return the resulting unwrapping
1555      */
1556     public static final Object unwrapRowShort(final int id) {
1557         if (arraySJO[id].object instanceof List) {
1558             return ScilabJavaArray.toShortArray((List<Short>) arraySJO[id].object);
1559         } else if (arraySJO[id].object instanceof Short[]) {
1560             return ScilabJavaArray.toPrimitive((Short[]) arraySJO[id].object);
1561         } else if (arraySJO[id].object instanceof ShortBuffer && !((ShortBuffer) arraySJO[id].object).isDirect()) {
1562             return ((ShortBuffer) arraySJO[id].object).array();
1563         }
1564
1565         return arraySJO[id].object;
1566     }
1567
1568     /**
1569      * @param id the Java Object id
1570      * @return the resulting unwrapping
1571      */
1572     public static final short[][] unwrapMatShort(final int id) {
1573         if (arraySJO[id].object instanceof Short[][]) {
1574             return (short[][]) ScilabJavaArray.toPrimitive(arraySJO[id].object);
1575         }
1576
1577         return (short[][]) (arraySJO[id].object);
1578     }
1579
1580     /**
1581      * @param id the Java Object id
1582      * @return the resulting unwrapping
1583      */
1584     public static final byte unwrapByte(final int id) {
1585         return ((Byte) (arraySJO[id].object)).byteValue();
1586     }
1587
1588     /**
1589      * @param id the Java Object id
1590      * @return the resulting unwrapping
1591      */
1592     public static final Object unwrapRowByte(final int id) {
1593         if (arraySJO[id].object instanceof List) {
1594             return ScilabJavaArray.toByteArray((List<Byte>) arraySJO[id].object);
1595         } else if (arraySJO[id].object instanceof Byte[]) {
1596             return ScilabJavaArray.toPrimitive((Byte[]) arraySJO[id].object);
1597         } else if (arraySJO[id].object instanceof ByteBuffer && !((ByteBuffer) arraySJO[id].object).isDirect()) {
1598             return ((ByteBuffer) arraySJO[id].object).array();
1599         }
1600
1601         return arraySJO[id].object;
1602     }
1603
1604     /**
1605      * @param id the Java Object id
1606      * @return the resulting unwrapping
1607      */
1608     public static final byte[][] unwrapMatByte(final int id) {
1609         if (arraySJO[id].object instanceof Byte[][]) {
1610             return (byte[][]) ScilabJavaArray.toPrimitive(arraySJO[id].object);
1611         }
1612
1613         return (byte[][]) (arraySJO[id].object);
1614     }
1615
1616     /**
1617      * @param id the Java Object id
1618      * @return the resulting unwrapping
1619      */
1620     public static final String unwrapString(final int id) {
1621         return (String) (arraySJO[id].object);
1622     }
1623
1624     /**
1625      * @param id the Java Object id
1626      * @return the resulting unwrapping
1627      */
1628     public static final String[] unwrapRowString(final int id) {
1629         if (arraySJO[id].object instanceof List) {
1630             return ScilabJavaArray.toStringArray((List<String>) arraySJO[id].object);
1631         }
1632
1633         return (String[]) (arraySJO[id].object);
1634     }
1635
1636     /**
1637      * @param id the Java Object id
1638      * @return the resulting unwrapping
1639      */
1640     public static final String[][] unwrapMatString(final int id) {
1641         return (String[][]) (arraySJO[id].object);
1642     }
1643
1644     /**
1645      * @param id the Java Object id
1646      * @return the resulting unwrapping
1647      */
1648     public static final boolean unwrapBoolean(final int id) {
1649         return (Boolean) (arraySJO[id].object);
1650     }
1651
1652     /**
1653      * @param id the Java Object id
1654      * @return the resulting unwrapping
1655      */
1656     public static final boolean[] unwrapRowBoolean(final int id) {
1657         if (arraySJO[id].object instanceof List) {
1658             return ScilabJavaArray.toBooleanArray((List<Boolean>) arraySJO[id].object);
1659         } else if (arraySJO[id].object instanceof Boolean[]) {
1660             return ScilabJavaArray.toPrimitive((Boolean[]) arraySJO[id].object);
1661         }
1662
1663         return (boolean[]) (arraySJO[id].object);
1664     }
1665
1666     /**
1667      * @param id the Java Object id
1668      * @return the resulting unwrapping
1669      */
1670     public static final boolean[][] unwrapMatBoolean(final int id) {
1671         if (arraySJO[id].object instanceof Boolean[][]) {
1672             return (boolean[][]) ScilabJavaArray.toPrimitive(arraySJO[id].object);
1673         }
1674
1675         return (boolean[][]) (arraySJO[id].object);
1676     }
1677
1678     /**
1679      * @param id the Java Object id
1680      * @return the resulting unwrapping
1681      */
1682     public static final char unwrapChar(final int id) {
1683         return (Character) (arraySJO[id].object);
1684     }
1685
1686     /**
1687      * @param id the Java Object id
1688      * @return the resulting unwrapping
1689      */
1690     public static final Object unwrapRowChar(final int id) {
1691         if (arraySJO[id].object instanceof List) {
1692             return ScilabJavaArray.toCharArray((List<Character>) arraySJO[id].object);
1693         } else if (arraySJO[id].object instanceof Character[]) {
1694             return ScilabJavaArray.toPrimitive((Character[]) arraySJO[id].object);
1695         } else if (arraySJO[id].object instanceof CharBuffer && !((CharBuffer) arraySJO[id].object).isDirect()) {
1696             return ((CharBuffer) arraySJO[id].object).array();
1697         }
1698
1699         return arraySJO[id].object;
1700     }
1701
1702     /**
1703      * @param id the Java Object id
1704      * @return the resulting unwrapping
1705      */
1706     public static final char[][] unwrapMatChar(final int id) {
1707         if (arraySJO[id].object instanceof Character[][]) {
1708             return (char[][]) ScilabJavaArray.toPrimitive(arraySJO[id].object);
1709         }
1710
1711         return (char[][]) (arraySJO[id].object);
1712     }
1713
1714     /**
1715      * @param id the Java Object id
1716      * @return the resulting unwrapping
1717      */
1718     public static final float unwrapFloat(final int id) {
1719         return (Float) (arraySJO[id].object);
1720     }
1721
1722     /**
1723      * @param id the Java Object id
1724      * @return the resulting unwrapping
1725      */
1726     public static final Object unwrapRowFloat(final int id) {
1727         if (arraySJO[id].object instanceof List) {
1728             return ScilabJavaArray.toFloatArray((List<Float>) arraySJO[id].object);
1729         } else if (arraySJO[id].object instanceof Double[]) {
1730             return ScilabJavaArray.toPrimitive((Float[]) arraySJO[id].object);
1731         } else if (arraySJO[id].object instanceof FloatBuffer && !((FloatBuffer) arraySJO[id].object).isDirect()) {
1732             return ((FloatBuffer) arraySJO[id].object).array();
1733         }
1734
1735         return arraySJO[id].object;
1736     }
1737
1738     /**
1739      * @param id the Java Object id
1740      * @return the resulting unwrapping
1741      */
1742     public static final float[][] unwrapMatFloat(final int id) {
1743         if (arraySJO[id].object instanceof Float[][]) {
1744             return (float[][]) ScilabJavaArray.toPrimitive(arraySJO[id].object);
1745         }
1746
1747         return (float[][]) (arraySJO[id].object);
1748     }
1749
1750     /**
1751      * @param id the Java Object id
1752      * @return the resulting unwrapping
1753      */
1754     public static final long unwrapLong(final int id) {
1755         return (Long) (arraySJO[id].object);
1756     }
1757
1758     /**
1759      * @param id the Java Object id
1760      * @return the resulting unwrapping
1761      */
1762     public static final Object unwrapRowLong(final int id) {
1763         if (arraySJO[id].object instanceof List) {
1764             return ScilabJavaArray.toLongArray((List<Long>) arraySJO[id].object);
1765         } else if (arraySJO[id].object instanceof Long[]) {
1766             return ScilabJavaArray.toPrimitive((Long[]) arraySJO[id].object);
1767         } else if (arraySJO[id].object instanceof LongBuffer && !((LongBuffer) arraySJO[id].object).isDirect()) {
1768             return ((LongBuffer) arraySJO[id].object).array();
1769         }
1770
1771         return arraySJO[id].object;
1772     }
1773
1774     /**
1775      * @param id the Java Object id
1776      * @return the resulting unwrapping
1777      */
1778     public static final long[][] unwrapMatLong(final int id) {
1779         if (arraySJO[id].object instanceof Long[][]) {
1780             return (long[][]) ScilabJavaArray.toPrimitive(arraySJO[id].object);
1781         }
1782
1783         return (long[][]) (arraySJO[id].object);
1784     }
1785
1786     /**
1787      * @param id the Java Object id
1788      * @return the identifier of the unwrappable type or -1 if nothing
1789      */
1790     public static final int isUnwrappable(final int id) {
1791         if (id == 0) {
1792             System.out.println("unwrappable=0");
1793             // Null object
1794             return 1;
1795         }
1796
1797         Integer t = unwrappableType.get(arraySJO[id].clazz);
1798         if (t != null) {
1799             return t;
1800         } else if (arraySJO[id].object instanceof List) {
1801             List l = (List) arraySJO[id].object;
1802             if (l.size() == 0 || l.get(0) == null) {
1803                 return -1;
1804             } else {
1805                 Class cl = l.get(0).getClass();
1806                 Integer i = listBaseType.get(cl);
1807                 if (i != null) {
1808                     for (Object o : l) {
1809                         if (o.getClass() != cl) {
1810                             return -1;
1811                         }
1812                     }
1813                 }
1814
1815                 if (i == null) {
1816                     return -1;
1817                 }
1818
1819                 return i;
1820             }
1821         } else if (arraySJO[id].object instanceof Buffer) {
1822             if (arraySJO[id].object instanceof DoubleBuffer) {
1823                 unwrappableType.put(arraySJO[id].clazz, 3);
1824                 return 3;
1825             } else if (arraySJO[id].object instanceof ByteBuffer) {
1826                 unwrappableType.put(arraySJO[id].clazz, 12);
1827                 return 12;
1828             } else if (arraySJO[id].object instanceof IntBuffer) {
1829                 unwrappableType.put(arraySJO[id].clazz, 24);
1830                 return 24;
1831             } else if (arraySJO[id].object instanceof CharBuffer) {
1832                 unwrappableType.put(arraySJO[id].clazz, 21);
1833                 return 21;
1834             } else if (arraySJO[id].object instanceof FloatBuffer) {
1835                 unwrappableType.put(arraySJO[id].clazz, 36);
1836                 return 36;
1837             } else if (arraySJO[id].object instanceof LongBuffer) {
1838                 unwrappableType.put(arraySJO[id].clazz, 30);
1839                 return 30;
1840             } else if (arraySJO[id].object instanceof ShortBuffer) {
1841                 unwrappableType.put(arraySJO[id].clazz, 18);
1842                 return 18;
1843             }
1844
1845             return -1;
1846         } else {
1847             return -1;
1848         }
1849     }
1850
1851     /**
1852      * Inner class to manage the free places
1853      */
1854     private static final class FreePlace {
1855
1856         int[] fp;
1857         int currentPos;
1858
1859         FreePlace() {
1860             this.fp = new int[INITIALCAPACITY];
1861             currentPos = -1;
1862         }
1863
1864         final void addFreePlace(final int n) {
1865             if (currentPos == fp.length - 1) {
1866                 int[] newFp = new int[(int) (1.5 * fp.length)];
1867                 System.arraycopy(fp, 0, newFp, 0, fp.length);
1868                 fp = newFp;
1869             }
1870             fp[++currentPos] = n;
1871         }
1872
1873         final int getFreePlace() {
1874             if (currentPos == -1) {
1875                 return -1;
1876             }
1877             return fp[currentPos--];
1878         }
1879
1880         final int[] getCurrentFreePlace() {
1881             if (currentPos == -1) {
1882                 return null;
1883             }
1884
1885             int[] ret = new int[currentPos + 1];
1886             System.arraycopy(fp, 0, ret, 0, ret.length);
1887
1888             return ret;
1889         }
1890     }
1891 }