1 /*
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 2002 The Apache Software Foundation. All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution, if
20 * any, must include the following acknowlegement:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowlegement may appear in the software itself,
24 * if and wherever such third-party acknowlegements normally appear.
25 *
26 * 4. The names "Apache BSF", "Apache", and "Apache Software Foundation"
27 * must not be used to endorse or promote products derived from
28 * this software without prior written permission. For written
29 * permission, please contact apache@apache.org.
30 *
31 * 5. Products derived from this software may not be called "Apache"
32 * nor may "Apache" appear in their names without prior written
33 * permission of the Apache Group.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many individuals
50 * on behalf of the Apache Software Foundation and was originally created by
51 * Sanjiva Weerawarana and others at International Business Machines
52 * Corporation. For more information on the Apache Software Foundation,
53 * please see <http://www.apache.org/>.
54 */
55
56 package org.apache.bsf.engines.activescript;
57
58 import java.util;
59 import java.io;
60 import java.lang.reflect;
61
62 import org.apache.bsf;
63 import org.apache.bsf.util;
64
65
66
67 /**
68 * This is the interface to active scripting engines from the Bean
69 * Scripting Framework. This code uses John Ponzo's IBM Active Scripting
70 * Toolkit to tie in active scripting engines to BSF.
71 * This class implements Runnable to create a thread. This thread is to
72 * exclusively access the scripting engine. All methods from this class to
73 * the engines is proxied over to the engine thread for execution. Why?
74 * Because, MS engines are implemented to only be accessed from ONE thread.
75 *
76 * @author Sanjiva Weerawarana
77 */
78 public class ActiveScriptEngine extends BSFEngineImpl implements JavaBeanAddEventListener
79 {
80
81 class ArrayInfo
82 {
83 protected Object arrayObject=null;
84 protected boolean investigated= false;
85 public int maxDepth=0;
86 // int curDepth=0;
87 public char type=0;
88 public int maxDimArray[]= null;
89 public int dimOffset[]= null;
90 public String toString()
91 {
92 if(0== maxDepth) return "Not an array";
93 String ret= "type="+type+",maxDepth="+ maxDepth+ "maxDimArray=\n";
94 for(int i=0; i < maxDepth; ++i) ret+= "["+ i+ "]"+"=" + maxDimArray[i] + ";\n";
95 return ret;
96 }
97
98 protected void investigate(Object o, int curDepth)
99 {
100 if(investigated) return;
101 if( null == o) return; //Safety
102
103 ++curDepth;
104 int thisDepth= curDepth;
105 if(thisDepth == maxDepth)
106 { //The reason the last dimension needs to be type specific to avoid getting runtime class cast exceptions on primatives!
107 switch( type)
108 {
109 case 'Z' :
110 {
111 boolean[] larray= (boolean []) o;
112 if(larray.length > maxDimArray[thisDepth-1]) maxDimArray[thisDepth-1]= larray.length;
113 }
114 break;
115 case 'B' :
116 {
117 byte[] larray= (byte []) o;
118 if(larray.length > maxDimArray[thisDepth-1]) maxDimArray[thisDepth-1]= larray.length;
119 }
120 break;
121 case 'C' :
122 {
123 char[] larray= (char []) o;
124 if(larray.length > maxDimArray[thisDepth-1]) maxDimArray[thisDepth-1]= larray.length;
125 }
126 break;
127 case 'S' :
128 {
129 short[] larray= (short []) o;
130 if(larray.length > maxDimArray[thisDepth-1]) maxDimArray[thisDepth-1]= larray.length;
131 }
132 break;
133 case 'I' :
134 {
135 int[] larray= (int []) o;
136 if(larray.length > maxDimArray[thisDepth-1]) maxDimArray[thisDepth-1]= larray.length;
137 }
138 break;
139 case 'J' :
140 {
141 long[] larray= (long []) o;
142 if(larray.length > maxDimArray[thisDepth-1]) maxDimArray[thisDepth-1]= larray.length;
143 }
144 break;
145 case 'F' :
146 {
147 float[] larray= (float []) o;
148 if(larray.length > maxDimArray[thisDepth-1]) maxDimArray[thisDepth-1]= larray.length;
149 }
150 break;
151 case 'D' :
152 {
153 double[] larray= (double[]) o;
154 if(larray.length > maxDimArray[thisDepth-1]) maxDimArray[thisDepth-1]= larray.length;
155 }
156 break;
157 default:
158 { //Should be an object
159 Object[] larray= (Object []) o;
160 if(larray.length > maxDimArray[thisDepth-1]) maxDimArray[thisDepth-1]= larray.length;
161 }
162 break;
163 }
164 }
165 else
166 { //Still a multi-dim array
167 Object[] larray= (Object []) o;
168 if(larray.length > maxDimArray[curDepth-1]) maxDimArray[curDepth-1]= larray.length;
169
170 for(int i=0; i < larray.length ; ++i)
171 {
172 if(larray[i].getClass().isArray() )
173 {
174 investigate(larray[i], thisDepth);
175 }
176 }
177 }
178 if(1== curDepth) investigated= true;
179 }//Endof investigate
180
181
182 private int setVariantData( Object o, byte v[], int os, int curDepth, int[] index) throws BSFException
183 {
184 ++curDepth;
185 if(curDepth != maxDepth)
186 {
187 Object[] larray= (Object []) o;
188 int i;
189 for( i=0; i< larray.length ; ++i)
190 {
191 if(larray[i] == null)
192 {
193
194 }
195 else
196 {
197 index[curDepth-1]=i;
198 for(int k= curDepth; k< maxDepth; index[k++]=0);
199 setVariantData( larray[i], v, os , curDepth, index );
200 }
201 }
202 }
203 else
204 {
205 switch( type)
206 {
207 case 'Z' :
208 {
209
210 boolean[] larray= (boolean[]) o;
211 int i;
212 int pos=os;
213 for(int k=0; k < curDepth-1; ++k) pos+= index[k]*dimOffset[k]*16;
214 for( i=0; i < larray.length; ++i)
215 {
216 int fpos= pos+ i*dimOffset[curDepth-1]*16;
217 v[fpos] = 11; //VT_BOOL
218 v[fpos+1] = 0;
219
220 byte x= (byte)( (larray[i]) ? 0xff: 0);
221 v[fpos+2]= x;
222 v[fpos+3]= x;
223 v[fpos+4]= x;
224 v[fpos+5]= x;
225 }
226 for(; i< maxDimArray[curDepth-1]; ++i )
227 {
228 int fpos= pos+ i*dimOffset[curDepth-1]*16;
229 v[fpos] = v[fpos+1]= 0; //VT_EMPTY
230 }
231
232 }
233 break;
234 case 'B' :
235 {
236 byte[] larray= (byte[]) o;
237 int i;
238 int pos=os;
239 for(int k=0; k < curDepth-1; ++k) pos+= index[k]*dimOffset[k]*16;
240 for( i=0; i < larray.length; ++i)
241 {
242 int fpos= pos+ i*dimOffset[curDepth-1]*16;
243 v[fpos] = 17; //VT_UI1
244 v[fpos+1] = 0;
245
246 int x= larray[i];
247 v[fpos+8]= (byte)x;
248 v[fpos+9]= v[fpos+10]= v[fpos+11]= 0;
249 }
250 for(; i< maxDimArray[curDepth-1]; ++i )
251 {
252 int fpos= pos+ i*dimOffset[curDepth-1]*16;
253 v[fpos] = v[fpos+1]= 0; //VT_EMPTY
254
255 }
256 }
257 break;
258 case 'C' :
259 {
260 char[] larray= (char[]) o;
261 int i;
262 int pos=os;
263 for(int k=0; k < curDepth-1; ++k) pos+= index[k]*dimOffset[k]*16;
264 for( i=0; i < larray.length; ++i)
265 {
266 int fpos= pos+ i*dimOffset[curDepth-1]*16;
267 v[fpos] = 17; //VT_UI1
268 v[fpos+1] = 0;
269
270 byte x= (byte) ((Character)o).charValue();
271 v[fpos+8]= x;
272 v[fpos+9]= v[fpos+10]= v[fpos+11]= 0;
273 }
274 for(; i< maxDimArray[curDepth-1]; ++i )
275 {
276 int fpos= pos+ i*dimOffset[curDepth-1]*16;
277 v[fpos] = v[fpos+1]= 0; //VT_EMPTY
278
279 }
280 }
281 break;
282 case 'S' :
283 {
284 short[] larray= (short[]) o;
285 int i;
286 int pos=os;
287 for(int k=0; k < curDepth-1; ++k) pos+= index[k]*dimOffset[k]*16;
288 for( i=0; i < larray.length; ++i)
289 {
290 int fpos= pos+ i*dimOffset[curDepth-1]*16;
291 v[fpos] = 2; //VT_I2
292 v[fpos+1] = 0;
293
294 int x= (int)larray[i];
295 v[fpos+8]= (byte)x;
296 v[fpos+9]= (byte)((x>>>8) & 0xff);
297 v[fpos+10]= (byte)((x>>>16) & 0xff);
298 v[fpos+11]= (byte)((x>>>24) & 0xff);
299 }
300 for(; i< maxDimArray[curDepth-1]; ++i )
301 {
302 int fpos= pos+ i*dimOffset[curDepth-1]*16;
303 v[fpos] = v[fpos+1]= 0; //VT_EMPTY
304
305 }
306 }
307 break;
308 case 'I' :
309 {
310 int[] larray= (int[]) o;
311 int i;
312 int pos=os;
313 for(int k=0; k < curDepth-1; ++k) pos+= index[k]*dimOffset[k]*16;
314 for( i=0; i < larray.length; ++i)
315 {
316 int fpos= pos+ i*dimOffset[curDepth-1]*16;
317 v[fpos] = 3; //VT_I4
318 v[fpos+1] = 0;
319
320 int x= larray[i];
321 v[fpos+8]= (byte)x;
322 v[fpos+9]= (byte)((x>>>8) & 0xff);
323 v[fpos+10]= (byte)((x>>>16) & 0xff);
324 v[fpos+11]= (byte)((x>>>24) & 0xff);
325 }
326 for(; i< maxDimArray[curDepth-1]; ++i )
327 {
328 int fpos= pos+ i*dimOffset[curDepth-1]*16;
329 v[fpos] = v[fpos+1]= 0; //VT_EMPTY
330
331 }
332 }
333 break;
334 case 'J' :
335 {
336 long[] larray= (long[]) o;
337 int i;
338 int pos=os;
339 for(int k=0; k < curDepth-1; ++k) pos+= index[k]*dimOffset[k]*16;
340 for( i=0; i < larray.length; ++i)
341 {
342 int fpos= pos+ i*dimOffset[curDepth-1]*16;
343 v[fpos] = 5; //VT_R8
344 v[fpos+1] = 0;
345
346 long x= Double.doubleToLongBits((double)(larray[i]));
347 v[fpos+8]= (byte)x;
348 v[fpos+9]= (byte)((x>>>8) & 0xff);
349 v[fpos+10]= (byte)((x>>>16) & 0xff);
350 v[fpos+11]= (byte)((x>>>24) & 0xff);
351 v[fpos+12]= (byte)((x>>>32) & 0xff);
352 v[fpos+13]= (byte)((x>>>40) & 0xff);
353 v[fpos+14]= (byte)((x>>>48) & 0xff);
354 v[fpos+15]= (byte)((x>>>56) & 0xff);
355
356 }
357 for(; i< maxDimArray[curDepth-1]; ++i )
358 {
359 int fpos= pos+ i*dimOffset[curDepth-1]*16;
360 v[fpos] = v[fpos+1]= 0; //VT_EMPTY
361 }
362 }
363 break;
364 case 'F' :
365 {
366 float[] larray= (float[]) o;
367 int i;
368 int pos=os;
369 for(int k=0; k < curDepth-1; ++k) pos+= index[k]*dimOffset[k]*16;
370 for( i=0; i < larray.length; ++i)
371 {
372 int fpos= pos+ i*dimOffset[curDepth-1]*16;
373 v[fpos] = 4; //VT_R4
374 v[fpos+1] = 0;
375
376 int x= Float.floatToIntBits(larray[i]);
377 v[fpos+8]= (byte)x;
378 v[fpos+9]= (byte)((x>>>8) & 0xff);
379 v[fpos+10]= (byte)((x>>>16) & 0xff);
380 v[fpos+11]= (byte)((x>>>24) & 0xff);
381 }
382 for(; i< maxDimArray[curDepth-1]; ++i )
383 {
384 int fpos= pos+ i*dimOffset[curDepth-1]*16;
385 v[fpos] = v[fpos+1]= 0; //VT_EMPTY
386
387 }
388 }
389 break;
390 case 'D' :
391 {
392 double[] larray= (double[]) o;
393 int i;
394 int pos=os;
395 for(int k=0; k < curDepth-1; ++k) pos+= index[k]*dimOffset[k]*16;
396 for( i=0; i < larray.length; ++i)
397 {
398 int fpos= pos+ i*dimOffset[curDepth-1]*16;
399 v[fpos] = 5; //VT_R8
400 v[fpos+1] = 0;
401
402 long x= Double.doubleToLongBits(larray[i]);
403 v[fpos+8]= (byte)x;
404 v[fpos+9]= (byte)((x>>>8) & 0xff);
405 v[fpos+10]= (byte)((x>>>16) & 0xff);
406 v[fpos+11]= (byte)((x>>>24) & 0xff);
407 v[fpos+12]= (byte)((x>>>32) & 0xff);
408 v[fpos+13]= (byte)((x>>>40) & 0xff);
409 v[fpos+14]= (byte)((x>>>48) & 0xff);
410 v[fpos+15]= (byte)((x>>>56) & 0xff);
411 }
412 for(; i< maxDimArray[curDepth-1]; ++i )
413 {
414 int fpos= pos+ i*dimOffset[curDepth-1]*16;
415 v[fpos] = v[fpos+1]= 0; //VT_EMPTY
416
417 }
418 }
419 break;
420 default:
421 { //Should be an object array.
422
423 Object[] larray= (Object[]) o;
424 int i;
425 int pos=os;
426 for(int k=0; k < curDepth-1; ++k) pos+= index[k]*dimOffset[k]*16;
427 for( i=0; i < larray.length; ++i)
428 {
429 int fpos= pos+ i*dimOffset[curDepth-1]*16;
430
431 if(larray[i] == null)
432 {
433 v[fpos] = 1; //VT_NULL
434 v[fpos+1] = 0;
435 }
436 else if(larray[i] instanceof java.lang.Boolean)
437 {
438 v[fpos] = 11; //VT_BOOL
439 v[fpos+1] = 0;
440 byte x= (byte)( (((Boolean) larray[i]).booleanValue()) ? 0xff: 0);
441 v[fpos+8]= x;
442 v[fpos+9]= x;
443 v[fpos+10]= x;
444 v[fpos+11]= x;
445 }
446 else if(larray[i] instanceof java.lang.Integer) //VT_R8
447 {
448 v[fpos] = 3; //VT_I4
449 v[fpos+1] = 0;
450 int x= ((Integer)larray[i]).intValue();
451 v[fpos+8]= (byte)x;
452 v[fpos+9]= (byte)((x>>>8) & 0xff);
453 v[fpos+10]= (byte)((x>>>16) & 0xff);
454 v[fpos+11]= (byte)((x>>>24) & 0xff);
455 }
456 else if(larray[i] instanceof String)
457 {
458 byte[] cppref= nativeStingToBString((String) larray[i]);
459
460 v[fpos] = 8; //VT_BSTR
461 v[fpos+1] = 0;
462
463 v[fpos+8]= cppref[0];
464 v[fpos+9]= cppref[1];
465 v[fpos+10]= cppref[2];
466 v[fpos+11]= cppref[3];
467 }
468 else if(larray[i] instanceof java.lang.Long) //VT_R8
469 { //COM has no long type so promote it to double which can contain it.
470 v[fpos] = 5; //VT_R8
471 v[fpos+1] = 0;
472 long x= Double.doubleToLongBits((double)(((Long)larray[i]).longValue()));
473 v[fpos+8]= (byte)x;
474 v[fpos+9]= (byte)((x>>>8) & 0xff);
475 v[fpos+10]= (byte)((x>>>16) & 0xff);
476 v[fpos+11]= (byte)((x>>>24) & 0xff);
477 v[fpos+12]= (byte)((x>>>32) & 0xff);
478 v[fpos+13]= (byte)((x>>>40) & 0xff);
479 v[fpos+14]= (byte)((x>>>48) & 0xff);
480 v[fpos+15]= (byte)((x>>>56) & 0xff);
481 }
482 else if(larray[i] instanceof java.lang.Short)
483 {
484 v[fpos] = 2; //VT_I2
485 v[fpos+1] = 0;
486 // int x= Float.floatToIntBits((larray[i]));
487 int x= ((Short)larray[i]).intValue();
488 v[fpos+8]= (byte)x;
489 v[fpos+9]= (byte)((x>>>8) & 0xff);
490 v[fpos+10]= (byte)((x>>>16) & 0xff);
491 v[fpos+11]= (byte)((x>>>24) & 0xff);
492 }
493 else if(larray[i] instanceof java.lang.Float)
494 {
495 v[fpos] = 4; //VT_R4
496 v[fpos+1] = 0;
497 int x= Float.floatToIntBits(((Float)larray[i]).floatValue());
498 v[fpos+8]= (byte)x;
499 v[fpos+9]= (byte)((x>>>8) & 0xff);
500 v[fpos+10]= (byte)((x>>>16) & 0xff);
501 v[fpos+11]= (byte)((x>>>24) & 0xff);
502 }
503 else if(larray[i] instanceof java.lang.Double) //VT_R8
504 {
505 v[fpos] = 5; //VT_R8
506 v[fpos+1] = 0;
507 long x= Double.doubleToLongBits(((Double)larray[i]).doubleValue());
508 v[fpos+8]= (byte)x;
509 v[fpos+9]= (byte)((x>>>8) & 0xff);
510 v[fpos+10]= (byte)((x>>>16) & 0xff);
511 v[fpos+11]= (byte)((x>>>24) & 0xff);
512 v[fpos+12]= (byte)((x>>>32) & 0xff);
513 v[fpos+13]= (byte)((x>>>40) & 0xff);
514 v[fpos+14]= (byte)((x>>>48) & 0xff);
515 v[fpos+15]= (byte)((x>>>56) & 0xff);
516 }
517 else if(larray[i] instanceof java.lang.Byte)
518 {
519 v[fpos] = 17; //VT_UI1
520 v[fpos+1] = 0;
521 byte x= ((Byte)larray[i] ).byteValue();
522 v[fpos+8]= x;
523 }
524 else if( larray[i] instanceof java.lang.Character)
525 {
526 v[fpos] = 17; //VT_UI1
527 v[fpos+1] = 0;
528 byte x= (byte) ((Character)larray[i] ).charValue();
529 v[fpos+8]= x;
530 }
531 else if( larray[i] instanceof java.lang.Void)
532 {
533 v[fpos] = 1; //VT_NULL
534 v[fpos+1] = 0;
535 }
536 else
537 { //Really some non-primative rep. object
538
539 byte[] cppref= null; // nativeObjectToVariant(css, larray[i]);
540
541 v[fpos] = 9; //VT_DISPATCH
542 v[fpos+1] = 0;
543
544 if(o instanceof org.apache.bsf.engines.activescript.COMIDispatchBean )
545 {
546 cppref = ((org.apache.bsf.engines.activescript.COMIDispatchBean )larray[i]).getIDispatchInterface();
547 }
548 else
549 {
550 cppref= nativeObjectToVariant(css, larray[i]);
551 }
552 System.arraycopy(cppref,0,v,fpos+8, cppref.length);
553 }
554 }
555 for(; i< maxDimArray[curDepth-1]; ++i )
556 {
557 int fpos= pos+ i*dimOffset[curDepth-1]*16;
558 v[fpos] = v[fpos+1]= 0; //VT_EMPTY
559 }
560 }//endof default
561 break;
562 }
563
564
565 }
566
567 return os;
568 }
569
570 byte [] toVariant()throws BSFException
571 {
572 investigate(arrayObject, 0);
573 int totalDimSize= maxDimArray[0];
574 for(int i=1; i < maxDepth; ++i) totalDimSize *= maxDimArray[i];
575 int mallocSize=16 + // Size of variant.
576 16 + // The size of a safeArray that follows.
577 8*maxDepth+ //The size of SAFEARRAYBOUND by the no of dim.
578 totalDimSize* 16;
579
580 byte[] v= new byte[mallocSize ]; //Size of each data item as a Variant.
581 v[0]= 12; //VT_ARRAY | VT_VARIANT
582 v[1]= 0x20; //VT_ARRAY
583
584 //SAFEARRAY IS PACKED AFTER THE VARIANT
585 v[16]= (byte)maxDepth; //cDims;
586 v[17]= (byte)((maxDepth>>>8) & 0xff);
587
588 v[18]= (byte) 0X92; //fFeatures = FADF_VARIANT
589 v[19]= 0X8;
590 //cbElements= 16 the size of a variant
591 v[20]= 16;
592 v[21]=v[22]=v[23]= 0;
593 //cLocks ??
594 v[24]=v[25]=v[26]=v[27]= 0;
595 int i=0, j=32;
596
597 //rgsabound[] one for each dimension. Has max no of elements for dim followed by staring base of index.
598 for(i=maxDepth-1; i >= 0 ; --i) //Kinda stored backward from what I expected.
599 {
600 v[j++]= (byte)( maxDimArray[i]);
601 v[j++]= (byte)((maxDimArray[i]>>>8) & 0xff);
602 v[j++]= (byte)((maxDimArray[i]>>>16) & 0xff);
603 v[j++]= (byte)((maxDimArray[i]>>>24) & 0xff);
604
605 v[j++]= 0; //Only support starting address of zero
606 v[j++]= 0;
607 v[j++]= 0;
608 v[j++]= 0;
609 }
610 //pvData addjusted on C++ side.
611 v[28]=v[29]=v[30]=v[31]= 0;
612 v[28]= (byte)(j);
613 v[29]= (byte)((j>>>8) & 0xff);
614 v[30]= (byte)((j>>>16) & 0xff);
615 v[31]= (byte)((j>>>24) & 0xff);
616
617 //THE DATA FOR THE SAFEARRAY IS PACKED AFTER IT
618 //Now for the data which will be a variant for each element. Note strings and true objects will need to be called back.
619 setVariantData( arrayObject, v, j, 0, new int[ maxDepth]);
620
621
622 return v;
623 }
624
625
626 ArrayInfo( Object o)
627 {
628 if( o.getClass().isArray())
629 {
630 String arrayClass= o.getClass().toString();
631 maxDepth= arrayClass.indexOf('[');
632 if(-1 != maxDepth)
633 {
634 arrayObject= o;
635 arrayClass= arrayClass.substring(maxDepth);
636 for(maxDepth=0; arrayClass.charAt(maxDepth) == '['; ++maxDepth);
637 type= arrayClass.charAt(maxDepth);
638 maxDimArray= new int[maxDepth];
639 dimOffset= new int[maxDepth];
640 investigate(o,0);
641 dimOffset[0]=1;
642 for(int i=1; i < maxDepth; ++i)
643 {
644 dimOffset[i]= dimOffset[i-1] * maxDimArray[i-1];
645 }
646 }
647
648 }
649 }
650 }
651 static BSFException dllLoadException= null; //Can hold an exception on from the loading of the c++ dll.
652 static final String libName= "bsfactivescriptengine"; //C++ dll name.
653
654 static final String LANG_VBSCRIPT = "vbscript";
655 static final String LANG_PERLSCRIPT = "perlscript";
656 static final String LANG_JSCRIPT = "jscript";
657
658 static {
659 try
660 {
661 System.loadLibrary (libName);
662 }
663 catch(java.lang.SecurityException e)
664 {
665 dllLoadException= new BSFException(BSFException.REASON_OTHER_ERROR, "SecurityException loading library:" + libName + " " + e.getMessage(),e);
666 }
667 catch(java.lang.UnsatisfiedLinkError e)
668 {
669 dllLoadException= new BSFException(BSFException.REASON_OTHER_ERROR, "UnsatisfiedLinkError loading library:" + libName + " " + e.getMessage(),e);
670 }
671
672 }
673 byte [] css= null;// c++ active script engine pointer, saved as an object and passed into the
674 BSFManager bsfmgr=null; //Used by other methods during JNI callbacks.
675 private Hashtable evalRet= null; //Used by languages which don't support expressions.
676 protected String lang= null; //The script language this engine is running.
677
678 /**
679 * add an event listener
680 */
681 public void addEventListener( Object bean, String event, String filter, String script) throws BSFException
682 {
683 EngineUtils.addEventListener(bean, event, filter, this, bsfmgr, "ActiveScriptEngine", 0, 0, script);
684 }
685 /**
686 * Binds a method to an integer so it can be later referenced to invoke the method via callMethod.
687 *
688 */
689 public final int bindMember(Object target, String name, short bindType) throws Exception
690 {
691 return JavaBean.bindMember( target.getClass(), name, bindType);
692 }
693 /**
694 * Return an object from an extension.
695 * @param method The name of the method to call.
696 * @param args an array of arguments to be
697 * passed to the extension, which may be either
698 * Vectors of Nodes, or Strings.
699 */
700 public Object call (Object object, String method, Object[] args)
701 throws BSFException {
702 StringBuffer sb = new StringBuffer (300);
703
704 sb.append (object.toString());
705 sb.append (".");
706 sb.append (method);
707 sb.append ("(");
708 if (args != null) {
709 for (int i = 0; i < args.length; i++) {
710 sb.append (args[i].toString ());
711 if (i < args.length-1) {
712 sb.append (",");
713 }
714 }
715 }
716 sb.append (")");
717 return eval ("<internal>", -1, -1, sb.toString ());
718 }
719 /**
720 * This function and (BSFCOM) should be eliminated once support in BSF to call methods with arrays is present.
721 * Java does not support variable number of arguments so the arguments to these are packed in an array in C++ land.
722 * The same holds true for the two functions following this one. ALSO BSFCOM c++ object might be able to be eliminated in
723 * the process.
724 */
725 private final Object callBeanMethod(Object target, String methodName, Object[] args ) throws org.apache.bsf.BSFException
726 {
727 if(target.equals(this) && methodName.equals("callMethodViaBSF")){ return callMethodViaBSF((Object [])args[0]);} //We know this is the only funtion for this method.
728 if(target.equals(this) && methodName.equals("createBean")){ return createBean((Object [])args[0]);} //We know this is the only funtion for this method.
729 return EngineUtils.callBeanMethod(target, methodName, args);
730 }
731 /**
732 * Invokes the method assocaited with methodID on the bean with parameters in the array args.
733 *
734 */
735 public final Object callMethod( Object bean, int methodID, Object[] args) throws Exception
736 {
737 return JavaBean.callMethod(this, bean, methodID, args);
738 }
739 /**
740 *
741 */
742 final Object callMethodViaBSF(Object []args) throws org.apache.bsf.BSFException
743 {
744 Object [] bsfargs= new Object[args.length-2];
745 if(args.length >2)System.arraycopy(args,2,bsfargs,0, args.length-2);
746 return EngineUtils.callBeanMethod(args[0], (String) args[1], bsfargs );
747 }
748 /**
749 * createBean
750 *
751 */
752 public final Object createBean(Object []args) throws org.apache.bsf.BSFException
753 {
754 Object [] bsfargs= new Object[args.length-1];
755 if(args.length >1)System.arraycopy(args,1,bsfargs,0, args.length-1);
756 return EngineUtils.createBean((String) args[0], bsfargs );
757 }
758 public static final Throwable createBSFException( int reason, String msg, Throwable t)
759 {
760 if(t != null) return new BSFException(reason, msg, t);
761 else return new BSFException(reason,msg);
762 }
763 /**
764 * Declare a bean after the engine has been started. Declared beans
765 * are beans that are named and which the engine must make available
766 * to the scripts it runs in the most first class way possible.
767 *
768 * @param bean the bean to declare
769 *
770 * @exception BSFException if the engine cannot do this operation
771 */
772 public final void declareBean (BSFDeclaredBean bean) throws BSFException
773 {
774 if(isVBScript()) exec("<declareBean>", 0, 0, "SET " + bean.name + "=bsf.lookupBean(\"" + bean.name + "\") 'via declareBean");
775 else if(isJScript()) exec("<declareBean>", 0, 0,"var " + bean.name + "=bsf.lookupBean(\"" + bean.name + "\"); //via declareBean");
776 else if(isPerlScript()) exec("<declareBean>", 0, 0, "$"+bean.name + "=$bsf->lookupBean('" + bean.name + "'); #via declareBean");
777 else throw new BSFException(BSFException.REASON_OTHER_ERROR, lang + " does not support declareBean.");
778 }
779 /**
780 * This is used by an application to evaluate a string containing
781 * some expression. ActiveScript engines don't return anything .. so
782 * the return value is awlays null.
783 */
784 public Object eval (String source, int lineNo, int columnNo, Object oscript) throws BSFException
785 {
786
787 if(!isPerlScript()) return nativeEval (css, source, lineNo, columnNo, oscript.toString (), true);
788 else
789 { //ActiveState's Perl implementation does not seem to support this so this was added to make it work.
790 Integer key=new Integer(Thread.currentThread().hashCode());
791 nativeEval (css, "<bsf perl declare>",lineNo, columnNo, "$bsf->setEvalRet(" + oscript.toString () + "); #via eval", false);
792 Object ret= evalRet.get(key);
793 if(ret== evalRet) ret = null;
794 evalRet.put(key, evalRet); //loose reference to whatever.
795 return ret;
796 }
797 }
798 /**
799 * This is used by an application to execute a string containing
800 * a script to execute. ActiveScript engines don't return anything .. so
801 * the return value is awlays null.
802 */
803 public void exec (String source, int lineNo, int columnNo, Object script) throws BSFException
804 {
805 //Run the script throw away any return code.
806 synchronized(this)
807 {
808 if(terminated()) throw new BSFException(BSFException.REASON_OTHER_ERROR, "Exec or eval called after engine termination!");
809 }
810 nativeEval (css, source, lineNo, columnNo, script.toString (), false);
811 }
812 protected void finalize() throws Throwable
813 {
814
815 terminate();
816 super.finalize();
817 }
818 public void initialize (BSFManager mgr, String language, Vector declaredBeans) throws BSFException
819 {
820 if(null != dllLoadException) throw dllLoadException;
821 synchronized(this)
822 {
823 if(null != lang)
824 { //Been called before... this is bad.
825 lang=language;
826 throw new BSFException(BSFException.REASON_OTHER_ERROR, "Engine " + this + " initialized again");
827 }
828 lang= language;
829 }
830
831 super.initialize (mgr, language, declaredBeans);
832 if(isPerlScript()) evalRet= new Hashtable(); //Used by languages which don't support expressions.
833 bsfmgr= mgr; //Save away so we can use duing JNI callback.
834
835
836 nativeInit (lang, null , null ); //Does not return unless exception or this engine is terminated.
837 //Delared beans are not declared using ActiveX Script's AddItem anymore since
838 // this does not allow to undeclare these beans later.
839 if(css == null)
840 { //Double check: nativeInit should have set this field!
841 throw new BSFException(BSFException.REASON_OTHER_ERROR, "Engine " + this
842 + " failed to initialize native interface properly.");
843 }
844
845 //Run a little script that sets up the declared beans.
846 // NOTE: this is done this way as opposed to doing it with MS com addnamedItem because
847 // this allows for undeclare of these beans to work.
848 if( 0 !=declaredBeans.size())
849 {
850 String prefix= "";
851 String bsf= "";
852 String suffix= "";
853 String eos="";
854 String eosLast="";
855 if(isVBScript())
856 {
857 prefix= "SET ";
858 bsf= "=bsf.lookupBean(\"";
859 suffix= "\")";
860 eos=":";
861 eosLast="";
862 }
863 else if(isJScript())
864 {
865 prefix= "var ";
866 bsf= "=bsf.lookupBean(\"";
867 suffix= "\")";
868 eos=";";
869 eosLast=eos;
870 }
871 else if(isPerlScript())
872 {
873 prefix= "$";
874 bsf= "=$bsf->lookupBean('";
875 suffix= "')";
876 eos=";";
877 eosLast=eos;
878 }
879 else throw new BSFException(BSFException.REASON_OTHER_ERROR, lang + " does not support undeclareBean.");
880
881 StringBuffer startup= new StringBuffer("");
882
883 int numDeclaredBeans= declaredBeans.size();
884 for(int i=0; i < numDeclaredBeans; ++i)
885 {
886 BSFDeclaredBean b=(BSFDeclaredBean)declaredBeans.elementAt(i);
887 startup.append(prefix+ b.name + bsf+ b.name + suffix + (i< (numDeclaredBeans-1)? eos : eosLast));
888 }
889 exec("<declareBean>", 0, 0, startup.toString());
890 }
891
892
893 }
894 protected final boolean isCaseSensitive() { return isVBScript();}
895 protected final boolean isJScript(){ return lang.equalsIgnoreCase( LANG_JSCRIPT);}
896 protected final boolean isPerlScript(){ return lang.equalsIgnoreCase( LANG_PERLSCRIPT);}
897 /*Unfortunately language identifiers necessary to handle language specific issues.*/
898 protected final boolean isVBScript(){ return lang.equalsIgnoreCase( LANG_VBSCRIPT);}
899 /**
900 * lookupBean
901 */
902 public final Object lookupBean(String name) // throws org.apache.bsf.BSFException
903 {
904 return bsfmgr.lookupBean(name);
905 }
906 private native Object nativeEval(byte[] css, String Source, int lineNo, int columnNo, String script, boolean evaluate) throws BSFException;
907 /*Native COM support routines */ //should go else where but easier here for now... lazy
908 static native void nativeIdispatchAddRef (byte[]IdispatchInterface) throws BSFException;
909 static native void nativeIdispatchDeleteRef (byte[]IdispatchInterface) throws BSFException;
910 /*Native routines*/
911 private native void nativeInit (String lang, String declaredBeanNames, Object[]declaredBeans) throws BSFException; //If all goes well sets css
912 private native byte[] nativeObjectToVariant(byte[] css, Object o) throws BSFException;
913 private native byte[] nativeStingToBString(String s) throws BSFException;
914 private native void nativeTerminate(byte[] css);
915 /**
916 * objectToVariant converts a java object to it's equivalent MS variant
917 * representation. Primitives are converted, objects and strings only have
918 * their types set.
919 *
920 * @param o the object which is to be converted to a variant.
921 * @return a byte array that has the image of a variant. SEE MS docs.
922 *
923 */
924 private final byte[] objectToVariant( Object o) throws BSFException
925 {
926 byte[] v= new byte[16]; //Size of a variant
927
928 if( null== o)
929 { //to be safe.
930 v[0] = 1; //VT_NULL
931 v[1] = 0;
932 }
933 else if(o instanceof java.lang.Boolean) //VT_R8
934 {
935 v[0] = 11; //VT_BOOL
936 v[1] = 0;
937 byte x= (byte)( (((Boolean) o).booleanValue()) ? 0xff: 0);
938 v[8]= x;
939 v[9]= x;
940 v[10]= x;
941 v[11]= x;
942 }
943 else if(o instanceof java.lang.Integer) //VT_R8
944 {
945 v[0] = 3; //VT_I4
946 v[1] = 0;
947 int x= ((Integer)o).intValue();
948 v[8]= (byte)x;
949 v[9]= (byte)((x>>>8) & 0xff);
950 v[10]= (byte)((x>>>16) & 0xff);
951 v[11]= (byte)((x>>>24) & 0xff);
952 }
953 else if( o instanceof java.lang.String)
954 {
955 v[0] = 8; //VT_BSTR
956 v[1] = 0;
957 }
958 else if(o instanceof java.lang.Long) //VT_R8
959 { //COM has no long type so promote it to double which can contain it.
960 v[0] = 5; //VT_R8
961 v[1] = 0;
962 long x= Double.doubleToLongBits((double)(((Long)o).longValue()));
963 v[8]= (byte)x;
964 v[9]= (byte)((x>>>8) & 0xff);
965 v[10]= (byte)((x>>>16) & 0xff);
966 v[11]= (byte)((x>>>24) & 0xff);
967 v[12]= (byte)((x>>>32) & 0xff);
968 v[13]= (byte)((x>>>40) & 0xff);
969 v[14]= (byte)((x>>>48) & 0xff);
970 v[15]= (byte)((x>>>56) & 0xff);
971 }
972 else if(o instanceof java.lang.Short)
973 {
974 v[0] = 2; //VT_I2
975 v[1] = 0;
976 int x= ((Short)o).intValue();
977 v[8]= (byte)x;
978 v[9]= (byte)((x>>>8) & 0xff);
979 v[10]= (byte)((x>>>16) & 0xff);
980 v[11]= (byte)((x>>>24) & 0xff);
981 }
982 else if(o instanceof java.lang.Float)
983 {
984 v[0] = 4; //VT_R4
985 v[1] = 0;
986 int x= Float.floatToIntBits(((Float)o).floatValue());
987 v[8]= (byte)x;
988 v[9]= (byte)((x>>>8) & 0xff);
989 v[10]= (byte)((x>>>16) & 0xff);
990 v[11]= (byte)((x>>>24) & 0xff);
991 }
992 else if(o instanceof java.lang.Double) //VT_R8
993 {
994 v[0] = 5; //VT_R8
995 v[1] = 0;
996 long x= Double.doubleToLongBits(((Double)o).doubleValue());
997 v[8]= (byte)x;
998 v[9]= (byte)((x>>>8) & 0xff);
999 v[10]= (byte)((x>>>16) & 0xff);
1000 v[11]= (byte)((x>>>24) & 0xff);
1001 v[12]= (byte)((x>>>32) & 0xff);
1002 v[13]= (byte)((x>>>40) & 0xff);
1003 v[14]= (byte)((x>>>48) & 0xff);
1004 v[15]= (byte)((x>>>56) & 0xff);
1005 }
1006 else if(o instanceof java.lang.Byte)
1007 {
1008 v[0] = 17; //VT_UI1
1009 v[1] = 0;
1010 byte x= ((Byte)o).byteValue();
1011 v[8]= x;
1012 }
1013 else if(o instanceof java.lang.Character)
1014 {
1015 v[0] = 17; //VT_UI1
1016 v[1] = 0;
1017 byte x= (byte) ((Character)o).charValue();
1018 v[8]= x;
1019 }
1020 else if(o instanceof java.lang.Void)
1021 {
1022 v[0] = 1; //VT_NULL
1023 v[1] = 0;
1024 }
1025 else if( o.getClass().isArray())
1026 {
1027 ArrayInfo ai= new ArrayInfo(o);
1028 v= ai.toVariant();
1029 }
1030 else
1031 { //Anything else just pray it's an object
1032 v[0] = 9; //VT_DISPATCH for object
1033 v[1] = 0;
1034
1035 byte[] cppref= null;
1036
1037 if(o instanceof org.apache.bsf.engines.activescript.COMIDispatchBean )
1038 {
1039 cppref = ((org.apache.bsf.engines.activescript.COMIDispatchBean )o).getIDispatchInterface();
1040 System.arraycopy(cppref,0,v,8, cppref.length);
1041 }
1042 else if(o instanceof org.apache.bsf.engines.activescript.vbEmpty) //Specific request to return back empty
1043 {
1044 v[0] = 0; //VT_EMPTY
1045 v[1] = 0;
1046 }
1047 else
1048 {
1049 cppref= nativeObjectToVariant(css, o);
1050 System.arraycopy(cppref,0,v,8, cppref.length);
1051 }
1052
1053 }
1054 return v;
1055 }
1056 public final void setEvalRet( Object ret)
1057 {
1058 evalRet.put( new Integer(Thread.currentThread().hashCode()) , ret != null ? ret : evalRet); //Had some problems setting the value to null.
1059 }
1060 public synchronized void terminate()
1061 {
1062 if(!terminated())
1063 {
1064 byte[] css= this.css;
1065 this.css= null;
1066
1067 bsfmgr=null; //Used by other methods during JNI callbacks.
1068 evalRet= null; //Used by languages which don't support expressions.
1069 lang=null;
1070 nativeTerminate(css); //Let c++ objects cleanup too.
1071 super.terminate();
1072 }
1073 }
1074 private final boolean terminated() {return null== css;} //Indicates object has offically terminated.
1075 /**
1076 * Undeclare a previously declared bean.
1077 *
1078 * @param bean the bean to undeclare
1079 *
1080 * @exception BSFException if the engine cannot do this operation
1081 */
1082 public void undeclareBean (BSFDeclaredBean bean) throws BSFException
1083 {
1084 if(isVBScript()) exec("<undeclareBean>", 0, 0, "SET " + bean.name + "=Nothing 'via undeclareBean");
1085 else if(isJScript()) exec("<undeclareBean>", 0, 0, bean.name + "=null; // via undeclareBean");
1086 else if(isPerlScript()) exec("<undeclareBean>", 0, 0, "undef " + bean.name + " ; #via undeclareBean");
1087 else throw new BSFException(BSFException.REASON_OTHER_ERROR, lang + " does not support undeclareBean.");
1088
1089 }
1090 }