JIMS: plug extraction
[scilab.git] / scilab / modules / external_objects_java / src / java / org / scilab / modules / external_objects_java / ScilabJavaArray.java
1 /*
2  * JIMS ( http://forge.scilab.org/index.php/p/JIMS/ ) - This file is a part of JIMS
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-en.txt
10  *
11  */
12
13 package org.scilab.modules.external_objects_java;
14
15 import java.lang.reflect.Array;
16 import java.lang.reflect.Method;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.logging.Level;
21
22 /**
23  * Tools for arrays
24  *
25  * @author Calixte DENIZET
26  */
27 @SuppressWarnings("serial")
28 public class ScilabJavaArray {
29
30     private static final Map<Class, Class> mappings = new HashMap<Class, Class>();
31     private static final Map<Class, Method> mappingsMethods = new HashMap<Class, Method>();
32
33     private static final Class[] EMPTYC = new Class[0];
34     private static final Object[] EMPTYO = new Object[0];
35
36     static {
37         mappings.put(Double.class, double.class);
38         mappings.put(Integer.class, int.class);
39         mappings.put(Boolean.class, boolean.class);
40         mappings.put(Short.class, short.class);
41         mappings.put(Byte.class, byte.class);
42         mappings.put(Character.class, char.class);
43         mappings.put(Long.class, long.class);
44         mappings.put(Float.class, float.class);
45
46         try {
47             mappingsMethods.put(Double.class, Double.class.getMethod("doubleValue", EMPTYC));
48             mappingsMethods.put(Integer.class, Integer.class.getMethod("intValue", EMPTYC));
49             mappingsMethods.put(Boolean.class, Boolean.class.getMethod("booleanValue", EMPTYC));
50             mappingsMethods.put(Short.class, Short.class.getMethod("shortValue", EMPTYC));
51             mappingsMethods.put(Byte.class, Byte.class.getMethod("byteValue", EMPTYC));
52             mappingsMethods.put(Character.class, Character.class.getMethod("charValue", EMPTYC));
53             mappingsMethods.put(Long.class, Long.class.getMethod("longValue", EMPTYC));
54             mappingsMethods.put(Float.class, Float.class.getMethod("floatValue", EMPTYC));
55         } catch (Exception e) { }
56     }
57
58     /**
59      * Create a wrapper for a Java Array object
60      * @param className the class to use
61      * @param dims the dimensions of the resulting array
62      * @param the id of the array
63      */
64     public static int newInstance(String className, int[] dims) throws ScilabJavaException {
65         Class cl = null;
66
67         if (ScilabJavaObject.debug) {
68             StringBuffer buf = new StringBuffer();
69             buf.append("(");
70             if (dims.length > 0) {
71                 int i = 0;
72                 for (; i < dims.length - 1; i++) {
73                     buf.append(Integer.toString(dims[i]));
74                     buf.append(",");
75                 }
76                 buf.append(Integer.toString(dims[i]));
77             }
78             buf.append(")");
79             ScilabJavaObject.logger.log(Level.INFO, "Array creation: base class is \'" + className + "\' with dims=" + buf.toString());
80         }
81
82         try {
83             int id = ScilabClassLoader.loadJavaClass(className, false);
84             if (id == 0) {
85                 cl = (Class) ScilabJavaObject.arraySJO[id].object;
86             } else {
87                 cl = Class.forName(className);
88             }
89         } catch (ClassNotFoundException e) {
90             throw new ScilabJavaException("Cannot find the class " + className);
91         }
92
93         return new ScilabJavaObject(Array.newInstance(cl, dims)).id;
94     }
95
96     /**
97      * Get an element in an array
98      * @param array the array
99      * @param index the index of the element to get
100      * @return the element
101      */
102     public static Object get(Object array, int[] index) throws ScilabJavaException {
103         Object obj = array;
104         for (int i = 0; i < index.length; i++) {
105             if (obj != null && obj.getClass().isArray()) {
106                 if (index[i] >= 0 && index[i] < Array.getLength(obj)) {
107                     obj = Array.get(obj, index[i]);
108                 } else {
109                     throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (Array.getLength(obj) - 1));
110                 }
111             } else if (obj instanceof List) {
112                 List list = (List) obj;
113                 if (index[i] >= 0 && index[i] < list.size()) {
114                     obj = list.get(index[i]);
115                 } else {
116                     throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (list.size() - 1));
117                 }
118             } else {
119                 throw new ScilabJavaException("Problem in retrieving " + i + "-th element: it is not an array");
120             }
121         }
122
123         return obj;
124     }
125
126     /**
127      * Set an element in an array
128      * @param array the array
129      * @param index the index of the element to set
130      * @param x the element
131      */
132     public static void set(Object array, int[] index, Object x) throws ScilabJavaException {
133         Object obj = array;
134         int i = 0;
135         for (; i < index.length - 1; i++) {
136             if (obj != null && obj.getClass().isArray()) {
137                 if (index[i] >= 0 && index[i] < Array.getLength(obj)) {
138                     obj = Array.get(obj, index[i]);
139                 } else {
140                     throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (Array.getLength(obj) - 1));
141                 }
142             } else if (obj instanceof List) {
143                 List list = (List) obj;
144                 if (index[i] >= 0 && index[i] < list.size()) {
145                     obj = list.get(index[i]);
146                 } else {
147                     throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (list.size() - 1));
148                 }
149             } else {
150                 throw new ScilabJavaException("Problem in retrieving " + i + "-th element: it is not an array");
151             }
152         }
153
154         if (obj != null && obj.getClass().isArray()) {
155             if (index[i] >= 0 && index[i] < Array.getLength(obj)) {
156                 try {
157                     Array.set(obj, index[i], x);
158                 } catch (IllegalArgumentException e) {
159                     throw new ScilabJavaException("Array " + obj + " cannot contain object which is an instance of " + x.getClass());
160                 }
161             } else {
162                 throw new ScilabJavaException("Problem in setting " + index[i] + "-th element: " + index[i] + ">" + (Array.getLength(obj) - 1));
163             }
164         } else if (obj instanceof List) {
165             List list = (List) obj;
166             if (index[i] >= 0 && index[i] < list.size()) {
167                 list.set(index[i], x);
168             } else if (index[i] == list.size()) {
169                 list.add(x);
170             } else {
171                 throw new ScilabJavaException("Problem in retrieving " + i + "-th element: " + index[i] + ">" + (list.size() - 1));
172             }
173         } else {
174             throw new ScilabJavaException("Problem in retrieving " + i + "-th element: it is not an array");
175         }
176     }
177
178     /**
179      * Convert a Double (or other type of the same kind) multiarray into a primitive double multiarray.
180      * (Take care: it is not a high performance function !!! if you have a better implementation, send it to me...)
181      * @param the array to convert, allowed types are: Double, Float, Integer, Character, Byte, Boolean, Short, Long
182      * @return the primitive array.
183      */
184     public static Object toPrimitive(Object array) {
185         /* TODO:
186            1) Verifier qu'on peut faire mieux avec des templates
187            2) Faire des tests (pas sur que ca passe...)
188         */
189         String info[] = getBasicType(array);
190         if (info == null) {
191             return null;
192         }
193         Class clazz;
194         try {
195             clazz = Class.forName(info[1]);
196         } catch (ClassNotFoundException e) {
197             return null;
198         }
199
200         Method method = mappingsMethods.get(clazz);
201         clazz = mappings.get(clazz);
202         if (clazz == null) {
203             return null;
204         }
205
206         int[] dims = new int[info[0].length()];
207         Object obj = array;
208         for (int i = 0; i < dims.length; i++) {
209             dims[i] = Array.getLength(obj);
210             obj = Array.get(obj, 0);
211         }
212
213         Object ret = Array.newInstance(clazz, dims);
214
215         int[] index = new int[dims.length - 1];
216         int last = dims.length - 1;
217         int pos = dims.length - 1;
218         try {
219             while (true) {
220                 Object arrG = array;
221                 Object arrS = ret;
222                 for (int i = 0; i < index.length; i++) {
223                     arrG = Array.get(arrG, index[i]);
224                     arrS = Array.get(arrS, index[i]);
225                 }
226                 for (int i = 0; i < dims[last]; i++) {
227                     Array.set(arrS, i, method.invoke(Array.get(arrG, i), EMPTYO));
228                 }
229                 pos = dims.length - 1;
230                 while (--pos >= 0 && index[pos] == dims[pos]) {
231                     ;
232                 }
233                 if (pos < 0) {
234                     break;
235                 }
236                 index[pos]++;
237                 for (int i = pos + 1; i < index.length; i++) {
238                     index[pos] = 0;
239                 }
240             }
241         } catch (Exception e) { }
242
243         return ret;
244     }
245
246     /**
247      * @param array an array
248      * @return the Object base type or null if it is not an Object
249      */
250     private static final String[] getBasicType(Object array) {
251         if (array != null && array.getClass().isArray()) {
252             String signature = array.toString();
253             String[] ret = new String[2];
254             int pos = 0;
255             while (signature.charAt(pos++) == '[') {
256                 ;
257             }
258             ret[0] = signature.substring(0, pos - 1);
259             int semicolon = signature.indexOf(';');
260
261             if (signature.charAt(pos - 1) == 'L') {
262                 ret[1] = signature.substring(pos, semicolon);
263                 return ret;
264             }
265         }
266
267         return null;
268     }
269 }