package org.rexxla.bsf.engines.rexx;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.concurrent.ConcurrentHashMap;
import java.util.StringTokenizer;

import java.util.*;
import java.io.*;
import java.lang.reflect.*;

import org.apache.bsf.*;
import org.apache.bsf.util.*;
import org.apache.bsf.util.type.*;

import static org.rexxla.bsf.engines.rexx.InvocationType.*;

/**
  * This class manages the calls from Rexx or Object Rexx into Java.
  * (Any scripting language being able to pass Strings to and
  * from Java will be able to use this interface, making it <em>really</em> easy to interface
  * with Java.)
  *
  *
 * <pre>------------------------ Apache Version 2.0 license -------------------------
 *    Copyright (C) 2001-2025 Rony G. Flatscher
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 * ----------------------------------------------------------------------------- </pre>
 *
  * @version 850, 2024-06-20
  * @author Rony G. Flatscher (<a href="http://www.wu-wien.ac.at">WU-Wien/Wirtschaftsuniversit&auml;t Wien</a>, <a href="http://www.wu-wien.ac.at/english">http://www.wu-wien.ac.at/english</a>)
  */


// ---rgf, 2016-11-27: leave it for backward compatibility as there are users of BSF4Rexx code for years to come
//
//                           - remove outdated EVENT_*, SyncPutGet (old eventListener support via BSF), can be done directly (easier, real-time)
//                           - check: is checking for object prefix in *registerBean() still necessary? YES: to allow mixing with pure BSF4Rexx code



 /*
     2025-08-27, rgf  - RexxEngine gets as its id value the Rexx instance identifier (.context~interpreter) to
                        ease debugging
     2024-06-20, rgf  - added Josep Maria to kudos
     2022-12-31, rgf  - added Till Winkler to kudos
     2022-09-02, rgf  - added argument string to jniCreateCollectionObject ()
     2022-09-01, rgf  - new protected native Object  jniCreateCollectionObject (Object[] slot, int kind)
                        to ease handler code, if it wants to set a context variable with information
                        in one of the following Rexx collections, kind: 0=Array, 1=Directory,
                        2=Stem, 3=StringTable

     2022-08-20, rgf  - new: getRexxConfiguration(), returns the RexxEngine's RexxConfiguration

     2022-08-19, rgf  - added new native methods to support new RexxRedirectedCommandHandler
                        native String jniRCH_ReadInput           (Object[] slot, int flag);
                        native byte[] jniRCH_ReadInputAsByteArray(Object[] slot);

                        native void jniRCH_WriteOutput(Object[] slot, int flag, String data);
                        native void jniRCH_WriteOutput(Object[] slot, byte[] data);

                        native void jniRCH_ErrorOutput(Object[] slot, int flag, String data);
                        native void jniRCH_ErrorOutput(Object[] slot, byte[] data);

     2022-08-10, rgf  - indicate by version number that this is for BSFooRexx 850:
                        - Java baseline:   1.8/8
                        - ooRexx baseline: 5.0

                      - changed type of rexxEngine from BSFEngine to RexxEngine, adjusted
                        also in argument; BSF4ooRexx.cc needs adjustment as well

     =========================================================================

     2022-08-06, rgf  - new case SIMPLE_EXECUTE_ARGUMENT, usage:
                        call BSF 'simpleExecute', [rexxCode], [rexxArgument]

     2022-07-20, rgf  - since using ConcurrentHashMap() there is no need to synchronize anymore

     2022-07-14, rgf  - changed RexxReflectUtil.loadClass() to not automatically register the
                        loaded class with the BSF registry, therefore LOAD_CLASS must do it instead

     2022-04-21, rgf  - add RAJBean.getName()

     2021-08-05, rgf  - removing finalize() which got deprecated for Java

                      - use PhantomReference as a replacement, ie., the RexxCleanupRef class
                        in the constructor

     2020-08-21, rgf: - if loaded from Rexx on Linux, and libBSF4ooRexx.so resides in /usr/local/lib
                        then it is not found as of Java 14, cf. <https://bugs.openjdk.java.net/browse/JDK-8073067>;
                        this version explicitly tries to load it from /usr/local/lib if not found by
                        System.loadLibrary("BSF4ooREXX");

     2019-11-26, rgf: - lookupBean(), little optimization: only lookup declared beans, if there are any

     2019-11-26, rgf: - lookupBean(): if not found in the registry looks up the new HashMap
                        RexxEngine.engineDeclaredBeans

     2019-11-14, rgf: - new method truncObject() to make sure that any Object's String value gets
                        truncated for better legibility in error messages

     2019-08-13, rgf: - fix Javadoc errors

     2019-02-07, rgf: - added subfunction "UNBOX": returns the unboxed value as a string or null, if not
                        a wrapped object

     2018-11-11, rgf: - fixed IS_INSTANCE where an exception was raised, if a plain string got supplied

     2018-11-03, rgf: - subfunction CREATE_STRICT_ARGUMENT: make it usable if not employing BSF.CLS
                      - some tidying up

     2018-11-02, rgf: - adjust arrayPutStrict() to use RexxStrictArgument directly to wrap primitive value

     2018-11-01, rgf: - changed convFromRexx() and coerceArgs() to use the new class RexxStrictArgument that
                        makes sure that only fields, methods and constructors get picked that strictly match
                        the classObject of RexxStrictArgument
                      - added new subfunction "strictArg" which will employ convFromRexx() and return a RexxStrictArgument;
                        meant to be used by box.strictArg() in BSF.CLS

     2018-03-22, rgf: - added Igor Petrushin to 'kudos': ported BSF4ooRexx for Raspberry Pi to ARM-32

     2018-03-22, rgf: - made sure that the NetRexx toString() method is fetched if the class
                        loading works in the catch part

     2018-02-26, rgf: - added native jniTestPing() method to allow for testing/debugging calls
                        via JNI to the native layer

     2018-02-22, rgf: - added static method "unregisterBean4JNI" to allow native code to decrease
                        the reference counter of the proxied Java object

                      - unregisterBean now returns the value of the reference counter or -1, if
                        not registered

                      - added method "getBeanRefCount" which returns the current value of the reference
                        counter or -1, if not registerd

     2018-02-22, rgf: - added number argument to BSF-subfunction "rexxReflectObject" which allows
                        for forcing e.g. to use RexxReflectJava6 even on much higher Java runtime
                        environments (argument "6") for testing purposes and as a last resort
                        fallback

     2018-02-19, rgf: - remove the jni methods jniForceConstructorNewInstance, jniForceFieldGet,
                        jniForceFieldSet, jniForceMethodInvoke as they cannot be used to force the
                        intended operations on Java 9; as the problem got solved by rewriting the
                        reflection part, these methods are not needed and get removed

                      - deprecated use of PROPERTY and EVENT subfucntions; first invocation will
                        show a deprecation warning

     2018-01-19, rgf: - define four JNI methods named jniForceConstructorNewInstance,
                        jniForceFieldGet, jniForceFieldSet, jniForceMethodInvoke (these "force"
                        JNI routines are means of last resort, if Java 9 or later is not
                        allowing to access protected members in superclasses via reflection
                        unlike all the previous versions of Java)

     2018-02-17, rgf: - new reflection logic added: "RexxReflect6.java" is for the Java 1.6/6 baseline
                        and Java 1.7/7; "RexxReflect7.java" compilable against Java 1.7/7, but will
                        be deployed against 1.8/8 (which has been tested to be reliable) and higher

                      - new subfunction "rexxReflectObject": will return the current RexxReflectJava* object in
                        use; allows querying and setting fundamental behaviour via the boolean attributes
                        "useCaching" on RexxReflectJava{6|7}, and on RexxReflectJava7 in addition the attributes
                        "useReflectInvoke" and "useUnreflect"

     2018-02-07, rgf: - coerceArgs(): allow from Rexx .true, "true", .false, "false" for boolean/Boolean, anything
                                      else will return null


     2018-01-09, ---rgf, - renamed GET_STATIC_VALUE* to GET_STATIC_FIELD_VALUE*
                         - removed 'private' modifier from: Object convFromRexx(String type, String value) throws BSFException

     2018-01-08, ---rgf, - changed switch to use new InvocationType enum

     2018-01-07, ---rgf - make sure access to rajRegistry is synchronized where values might get changed
                        - changed static private int constants (indicating the desired function from Rexx)
                          to package private to allow RexxReflect* classes access them

     2018-01-06, ---rgf: remove deprecation warning of the Java 9 compiler, if there is a Java 6 compliant,
                         non-deprecated alternative; note: the deprecation warning on "finalize" will not
                         be honored as this is intentional as it is the only means to allow garbage collection
                         on the Rexx side as well, when Java Rexx peers get out of scope

     2018-01-05, ---rgf: turn utility methods into static:


                        RexxAndJava.java

                        -    static Object [] coerceArgs(Object [] funcArgs, Class [] paramTypes)
                        -    static protected String makeString4Rexx(Object o)  // changed 2003-01-06 from "makeResultString()" to "makeString4Rexx()"
                        -    static public String makeBeanName(Object o)
                        -    static protected String registerBean(String beanName, Object object)
                        -    static protected Object lookupBean(String beanName)
                        -    static int spilloverCounter=0;

                        - added new instance method for native code compatibility:

                             private String makeString4Rexx(Object o)

                        Need to supply RexxAndJava object/instance (named "rajo") to now static methods:

                            Need to supply "bTerminated" to now static method:
                            -    static protected String registerBean(String beanName, Object object)
                            Need to supply or change "this" to RexxAndJava.class to now static method:
                            -    static protected Object lookupBean(String beanName)
                            -    static protected String registerBean(String beanName, Object object)
                            -    static public String makeBeanName(RexxAndJava rajo, Object o)


     2018-01-04, ---rgf, - ARRAY_PUT with Boolean/boolean component type will now behave like SET PROPERTY_VALUE
                           and SET_FIELD_VALUE:
                           if Rexx string is "1" (.true) then Boolean.TRUE will be used, otherwise the
                           type convertor will create the Boolean value (which means that a Rexx string
                           value named "true" will yield Boolean.TRUE as well, otherwise BOOLEAN.FALSE,
                           which follows from using java.lang.Boolean.valueOf(String))

     2018-01-01, ---rgf, - fixed a bug in ARRAY_PUT: only use the type convertor, if convFromRexx() returns
                           a string value and the component type is primitive, otherwise use the Object
                           value convFromRexx() returned

     2017-04-04, ---rgf, - removed debug-output in registerBean4JNI()

     2016-12-20, ---rgf, - remove rii_id in unregisterBean, not needed anymore

     2016-12-19, ---rgf, - refactoring the new registry code such that we can save calls from the instance
                           *Registry*() to the static *Registry*()-methods

     2016-12-08, ---rgf, - tidying up code, removing all code relating to the Java registry changes/additions
                           of 2015-08-03, new central Java registry replaces it

     2016-11-28, ---rgf, - convFromRexx(): check that type string is not the empty string, change error message
                           to be more meaningful
                         - fixing a subtle bug where even invokestrict() may be fooled in method chosing: e.g.
                           java.lang.List possesses two remove methods with the signature "Object remove(int)"
                           and "boolean remove(Object)". The current algorithm in INVOKE_STRICT can be misled
                           to choose the wrong method if checking the "remove(Object)" first (because an Integer
                           object, to which the primitive int value was converted to already, could be used as
                           an argument). Now checking if argument must be primitive, so not to accept a parameter
                           of type Object.


     2016-11-27, ---rgf, - new central RAJRegistry with RAJBeans, global to all Rexx interpreter instances
                         - turning bsfPrefixReturnValue into static to become available in static methods
                         - make glob_tcr static

     2016-11-19, ---rgf, - updated major version number to 6 to indicate new base level Java 1.6/6

     2016-11-12, ---rgf, change from .isAssignableFrom() to .isInstance() when checking whether MAKEARRAY/SUPPLIER
                    could be honored

     2016-11-06, ---rgf, if non-existing MAKEARRAY or SUPPLIER methods should be invoked, then check, whether
                    we have a Java collection in hand that has one of the following interfaces implemented:
                    java.lang.Iterable, java.util.Collection, java.util.Enumeration, java.util.Iterator or
                    java.util.Map. If so, then create and return a genuine Rexx object of type .Array or
                    .Supplier wrapped as a RexxProxy which can be unwrapped on the ooRexx side using BsfRexxProxy(rp,"o")
                    as will be done in BSF.CLS' class BSF.

                    In addition treat a Java class object of type java.lang.Enum as a collection of enum values
                    and return them for MAKEARRAY; in the case of SUPPLIER use the ordinal enum values for the index
                    array and the enum values for the item array

     2016-11-04, ---rgf, - basing on 1.6/6.0, get rid of generic warnings
                    source_java>javac -Xlint:unchecked RexxAndJava.java
                    RexxAndJava.java:543: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type java.util.HashMap
                            pendingUninits.put(new_rii_ID, new ArrayList(64));
                                              ^
                    RexxAndJava.java:711: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type java.util.HashMap
                                    pendingUninits.put(rii_ID, new ArrayList(64));
                                                      ^
                    RexxAndJava.java:4070: warning: [unchecked] unchecked call to isAssignableFrom(java.lang.Class<?>) as a member of the raw type java.lang.Class
                                                                  bFound=(paramTypes[j].isAssignableFrom(funcArgs[j].getClass()));
                                                                                                        ^
                    RexxAndJava.java:5179: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.ArrayList
                                                              al.add(args[1]);
                                                                    ^
                    RexxAndJava.java:5594: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type java.util.Hashtable
                                           orxReferences.put(beanName, newRefCount); // remember refCount
                                                            ^
                    RexxAndJava.java:5911: warning: [unchecked] unchecked call to isAssignableFrom(java.lang.Class<?>) as a member of the raw type java.lang.Class
                                    if (!(paramTypes[k].isAssignableFrom (funcArgs[k].getClass()))) // not compatible, break
                                                                         ^
                    RexxAndJava.java:5957: warning: [unchecked] unchecked call to getConstructor(java.lang.Class<?>...) as a member of the raw type java.lang.Class
                                            Constructor constr=paramTypes[k].getConstructor( argClass );
                                                                                           ^
                    RexxAndJava.java:6167: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type java.util.Hashtable
                                orxReferences.put(beanName, new Integer(refCount)); // remember refCount
                                                 ^
                    RexxAndJava.java:6173: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.HashSet
                                        beansCreated.add(beanName);
                                                        ^
                    RexxAndJava.java:6236: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type java.util.Hashtable
                                       orxReferences.put(beanName, new Integer(refCount));
                                                        ^
                    RexxAndJava.java:6597: warning: [unchecked] unchecked call to addElement(E) as a member of the raw type java.util.Vector
                                               eventTextVectorHigh.addElement(o);   // changed to addElement() for JRE 1.1.8, ---rgf
                                                                             ^
                    RexxAndJava.java:6601: warning: [unchecked] unchecked call to addElement(E) as a member of the raw type java.util.Vector
                                               eventTextVectorLow.addElement(o);    // changed to addElement() for JRE 1.1.8, ---rgf
                                                                            ^
                    RexxAndJava.java:6606: warning: [unchecked] unchecked call to addElement(E) as a member of the raw type java.util.Vector
                                               eventTextVector.addElement(o);       // changed to addElement() for JRE 1.1.8, ---rgf
                                                                         ^
                    RexxAndJava.java:6764: warning: [unchecked] unchecked call to <T>toArray(T[]) as a member of the raw type java.util.ArrayList
                                    entries=(String[]) al.toArray(entries);
                                                                 ^
                    14 warnings



     2016-08-14, ---rgf, - updated kudos-entries
     2015-08-03, ---rgf, - change code to only deregister bean, if running in the context of the same RII
                           in which registering took place!

                           - defining a class field "pendingUninits": a HashMap<String,HashSet> (RII_ID,Vector of beanNames to unregister)

                           - case "UNREGISTER_BEAN" adopted accordingly

                           - terminate: make sure all registered beans get deregistered (BSFManager may
                                        initiate a new Rexx interpreter instance which should be able to
                                        access any other registered Java object)

     2015-08-01, ---rgf, - change error message "method not found or error (exception) executing method!" to
                           unambiguous message: "(exception) executing method!"
                         - add subfunction "get_RII_ID", which returns the "Rexx interpreter instance ID" (a string)

     2015-07-27, ---rgf, - make sure that no (added) debug statements are carried out

     2015-05-09, ---rgf, - added access to important Rexx objects and interpreter related information
                           - protected native Object jniGetLocalEnvironment0
                           - protected native Object jniGetGlobalEnvironment0
                           - protected native Object jniNil0
                           - protected native long   jniInterpreterVersion0
                           - protected native long   jniLanguageLevel0

     2014-10-04, ---rgf, - add subfunctions that return a reference to a java.lang.String object or
                           a NetRexx object, if such a value needs to be returned (rather than turning
                           it into a Rexx string), added subfunctions:

                               - getFieldValueJSO
                               - getFieldValueStrictJSO
                               - getPropertyValueJSO
                               - getStaticStrictValueJSO
                               - getStaticValueJSO
                               - invokeJSO
                               - invokeStrictJSO

     2014-05-15, ---rgf, - correct new method lookup for INVOKE (did not find fields, nor was coercing
                           the arguments, rather used the INVOKE_STRICT logic)

     2014-05-14, ---rgf, - change method lookup for INVOKE to use Class.getMethods() instead of Class.getDeclaredMethods();
                           getMethods() returns all public methods, which in Java 8 also includes default (interface) methods,
                           if necessary

     2014-04-02, ---rgf, - move initialization of JNI library to RexxAndJava constructor to make
                           sure that non-Rexx JNI functions are available to Java (like jniProcEnvironment())

     2014-03-29, ---rgf, - add jniProcEnvironment(...): this allows to get, set and unset the
                           process environment from Java; reason: AOO 4.x removes the PATH environment
                           variable (seems to be unintended, hence an error), which inhibits the
                           Rexx interpreter to initialize successfully; this jni function is intended
                           to allow as a last resort to set the missing PATH environment variable;
                           the subfunctions "getEnv" and "setEnv" will not be explicitly documented

     2013-06-25, ---rgf, - add a terminate() method which nullifies the peer BSFManager and RexxEngine
                           object to allow a terminated BSFManager RexxEngine to be garbage collected

     2013-01-04, ---rgf, - use alternative code to fix bug https://sourceforge.net/tracker/?func=detail&aid=3599351&group_id=400586&atid=1660873

     2013-01-03, ---rgf, - fix bug https://sourceforge.net/tracker/?func=detail&aid=3599351&group_id=400586&atid=1660873

     2012-11-01, ---rgf, - fix bug https://sourceforge.net/tracker/?func=detail&aid=3581957&group_id=400586&atid=1660873

     2012-04-17, ---rgf, - fixed a bug in createRexxInterpreterInstance() where the new RII was
                           not assigned to the RexxEngine if that had no RII assigned to it yet
                         - added protected void set_rii_ID(String rii_ID) to allow Java4Rexx to
                           set the reference to the Rexx interpreter instance that invoked it
                         - tidying up the code a bit (removing comments and TODOs that are not actual anymore)

     2012-03-12, ---rgf, - now loading BSF4ooRexx DLL/so after trying to fetch the netrexx.lang.Rexx class,
                           such that native library can access static field "nlR_class" and fetch the class object,
                           if Java found it
                         - change scope of "bsfPrefixReturnValue" from static to instance, such that
                           the Rexx interpreter instances can run with different settings

     2012-02-25, ---rgf, - added methods jniNil(), jniInterpreterVersion(), jniLanguageLevel()
     2012-02-24, ---rgf, - added methods jniGetLocalEnvironment(), jniGetGlobalEnvironment()

     2012-02-19, ---rgf, - added methods jniGetCallerContext(), jniGetAllContextVariables

     2012-02-11, ---rgf, - added methods:
                           jniCheckCondition(), jniClearCondition(), jniGetConditionInfo(),
                           jniSetThread(), jniSetThreadTrace(), jniHaltThread()

     2012-02-08, ---rgf, - added methods:
                           jniRaiseCondition(), jniRaiseException(), jniRaiseException0(),
                           jniRaiseException1(), jniRaiseException2(), jniGetContextVariable(),
                           jniSetContextVariable()

     2012-02-06, ---rgf, - changed visibility of all jni*()-functions from public to protected
                         - changed jniRegisterBSF() to jniSetupNativeJVMPointer() to reflect the current purpose
                         - changed jniRexxCreateInterpreterInstance to accept new options argument
                         - added private field "rii_ID" and getter "get_rii_ID()", could also be inferred via field "rexxEngine"



     -------------------------------------- before adding functionality to configure the Rexx interpreter instance

     needs: Java level 1.4 due to using Exception's getCause();
            ooRexx 4.0
     2011-06-04, ---rgf, - make sure that BSFExceptions get the Throwable assigned, if this
                           intelligible from context, such that one can retrieve it by using
                           the BSFException instance method getTargetException()

     2011-03-15, ---rgf, - add new persons to credit/kudos

     2011-02-23, ---rgf, - as this class is not public, its public members cannot be accessed
                           by non-package code; therefore added that a new subfunction
                           "carryOutSystemExit": if no argument ("0"|.false or "1"|.true) is given,
                           then the current setting will be returned, otherwise the boolean field
                           will be set to the argument, which gets returned as well

     2011-02-09, ---rgf, - added static public boolean field 'bCarryOutSystemExit': if set to false,
                           then the subfunction EXIT does not carry out a delayed System.exit (ignores it);
                           this allows BSF4ooRexx programs like 'ooRexxTry.rxj' to execute BSF4ooRexx
                           programs that employ bsf.exit, which - if carried out - would exit Java and
                           by that means will shut down 'ooRexxTry.rxj'

     2011-01-24, ---rgf, - add new persons to credit

     2010-05-22, ---rgf, - removed special handling of Character.class or char.class arguments because
                           of changes in BSF4ooRexx.cc

     2010-05-20, ---rgf, - fixed a bug in converting to a char or Character, if the value was "00"x
                         - coerceArgs(): if matching wrapper objects are passed for primitive values
                                         from Rexx, then accept them from now on

     2010-04-20, ---rgf, - fixed a bug in INVOKE, if looking up and resolving a method on class-objects

     2010-04-18, ---rgf, - changed logic in REGISTER_BEAN | NEW (matching changed logic in
                           BSF.CLS' .BSF~bsf.import): Java class object is already loaded,
                           hence just look it up in the registry

     2010-04-17, ---rgf, - fixed conversion error in setFieldValue[Strict], if assigning "1" to a boolean

     2010-03-27, ---rgf, - getCauseAsString() now if processing an InvocationTargetException then
                           first attempts to do a getTargetException(), if not successful falls back
                           to current getCause().

     2010-02-20, ---rgf, - added isA|instanceOf(jObject, jClass)

     2009-10-31, ---rgf, - replaced European chars with their Unicode values
                         - made error message for BSFREGISTRY more informative for the programmer

     2009-10-19, ---rgf, - renaming "BSF4Rexx" to "BSF4ooRexx"
     2009-10-18, ---rgf, - added private methods "lookupBean4JNI" and "registerBean4JNI"
     2009-10-12, ---rgf, - allow "getRAJO" as synonym for "getRexxAndJava"

     2009-10-07, ---rgf, - allow retrieving this RexxEngine instance

     2009-10-02, ---rgf, - allow retrieving this RexxAndJava instance

     2009-09-10, ---rgf, - added a synonym "createJavaArrayOf" for "createArrayOf" to make this self-documuntary
                           clear that a Java array object is to be created and not an ooRexx one
                         - added a synonmym "createJavaArray" for "createArray": this allows to make
                           it clear that a Java array object is to be created and not an ooRexx one

     2009-08-27, ---rgf, - added the argument "returnType" to rexxInterface.jniRexxSendMessageToRexxObject()
                         - added private method "convFromJNI(type,value)"
     2009-07-30, ---rgf, - adding subfunction "createArrayOf": creates a single dimensioned
                           Java array and returns it; the first argument determines the type of the
                           array ("componentType"); all subsequent values in the array are then coerced
                           to the "componentType" and stored. If no values are given (just the single
                           "componentType") then the Java array will have a size of "0", but still being
                           of the given "componentType"
     2009-07-14, ---rgf, - treat Boolean in "convFromRexx(typeIndicator,value)" string "true" as Boolean
                           (so far only "1" = Rexx truth value was regarded as "true"); because of the
                           typeIndicator it is clear that a Boolean (string) value is submitted; allowing
                           the (caseless) string "true" will make transcriptions from Java programs easier

     2009-07-13, ---rgf, - corrected a bug in INVOKE and INVOKE_STRICT, if object was a class object
                         - applying System.identityHashValue() for all Java objects, as we truly need
                           uniquely identifiable peers

     2009-07-12, ---rgf, - renamed argument "methodDescription" to "methodDescriptor" for
                           jniRexxSendMessageToRexxObject()

     2009-07-11, ---rgf, - added arguments "javaObject" and "methodDescription" to
                           jniRexxSendMessageToRexxObject()

     2009-06-27, ---rgf, - changed signature of jniRexxSendMessageToRexxObject() to accept the
                           beanname of an optional Java method object

     2009-06-25, ---rgf, - CREATE_ARRAY_OBJECT: now also accepts a string denoting a fully qualified
                           Java class as its component type

     2009-06-23, ---rgf, - removed argument "creationTID" in jniRexxSendMessageToRexxObject (...)

     2009-06-20, ---rgf, - subfunction POLL_EVENT_TEXT: now checks for correct number of arguments and
                           checks that timeout value is not negative, if supplied

     2009-06-07, ---rgf, - removed subfunction "addEventListenerReturningEventInfos",
                           use new external Rexx function BsfCreateRexxProxy() instead

     2009-05-.., ---rgf, - added jniCreateInterpreterInstance
                         - added jniGetRexxInterpreterInstanceRoot
                         - added jniRexxRunProgram
                         - added jniRexxSendMessageToRexxObject
                         - added jniUnregisterRexxObject
                         - added jniRexxHaltInterpreterInstance
                         - added jniRexxTerminateInterpreterInstance

     2009-05-04, ---rgf, - added getRexxEngine() accessor

     // ===================================== pre-4.0 editions
     2009-05-01, ---rgf, - made output of arguments in 'invoke' and 'invokeStrict' better ledgible and
                           more informative

     2009-04-02, ---rgf, - added 'jniRexxGetTID()', 'jniRexxSetHalt(tid)'
                         - added new subfunction 'haltThread'

     2008-09-09, ---rgf, - 'unregisterBean' returns the beanName, if unregistering could take
                           place, .nil else (because refCounter is not 0 yet)

     2008-09-08, ---rgf, - fixed bugs in return string in subfunctions "new|register[strict]"
                           and "unregister"

     2008-09-01, ---rgf, - removed undocumented, experimental subfunction
                           "getOrLoadClass(JavaClassName)"

     2008-08-28, ---rgf, - added rawRegisterBean(beanName,object)

     2008-08-26, ---rgf, - added new subfunction "getOrLoadClass(JavaClassName)"

     2008-06-,23, ---rgf, if method javaCallBSF() is invoked recursively, don't apply
                          makeString4Rexx() to the result, as that got applied already at that
                          point in time

     2008-06-22, ---rgf, - after 7 hrs of debugging found and fixed a subtle bug in
                           combination of BSF.CLS' algorithm to determine a bean: returning the
                           beanname as a string causes BSF.CLS to create a BSF_REFERENCE which will
                           cause deregestering the bean from the BSFRegistry whenever the ooRexx
                           reference object goes out of scope, invalidating any other references
                           to the Java object!
                         - added a new BSF-subfunction "bsfPrefixReturnValue([.true|.false])" which
                           controls whether makeString4Rexx() prepends the return value (always a
                           string) with "<O>" (following string is index to BSFRegistry) or
                           "<S>" (plain string follows); will be set by BSF.CLS to allow BSF.WRAP()
                           to unanimously distinguish between string values and object string
                           references
     2008-06-14, ---rgf, passing "scriptSourceLocation" to jniRexxStart()
     2008-06-13, ---rgf, added a missing "]" in an output string
     2008-06-08, ---rgf, if an InvocationTargetException()-exception, then show its contained exception message
                         to ease identifying the cause of the exception
     2008-06-05, ---rgf, if EngineUtils.loadClass() in BSF 2.4 returns "null", then make sure that a
                         class-not-found exception is thrown; BSF should take care of that in the future
     2007-09-21, ---rgf, now using updated "EngineUtils.loadClass(...)" under all circumstances
     2007-01-28, ---rgf, changed "EngineUtils.loadClass(...)" to use instead the Thread's context class loader
     2006-12-10, ---rgf, changed subfunction "version" to accept one argument which indicates which
                         version to return (BSFManager or one of the org.rexxla.bsf.eninges.rexx
                         classes)

     2006-12-08, ---rgf, added subfunction "getBSFManager"; this allows retrieving the
                         BSF version, but also employing other scripts sharing the same
                         BSF registry

     2006-11-19, ---rgf, add transparent NetRexx support, ie. treat "netrexx.lang.Rexx" like
                         "java.lang.String"

     2006-08-01, ---rgf, make sure that the created beanName is unique even in the case of
                         java.lang.reflect.Constructor (which on Sun's Java returns the same
                         hashCode()-value for all of its instances!)
     2006-05-29, ---rgf, fixed bugs in coercing Rexx string values to Boolean and Character using BSF's
                         rather relaxed conversion infrastructure; this caused wrong methods to be picked
                         in "java.io.PrintBuffer" "println()" methods at times;
                         now Boolean *must* be either the Rexx values "0" or "1" and if
                         a character is tried, then the Rexx string must consist of exactly one character;
                         should that (very unlikely) sometimes yield a wrong method to be picked, then you
                         need to use the "bsf.invokeStrict" subfunction or BSF method, which allows you to
                         exactly indicate the type of the argument for the method to be picked

     2006-02-24, ---rgf, added "addEventListenerReturningEventInfos"
     2006-02-15, ---rgf, fixed the Java access error for method invocation, if method is public, but
                         object reference is from a non-public class (like an inner class, eg. Enumeration)
     2006-02-07, ---rgf, fixed an error in "invoke:" (eternal loop, if method not found)
     2006-02-05, ---rgf, not using BSF anymore for invoking methods; reason: if Class' methods need to be
                         invoked via class objects, this is not possible with BSF; changing BSF itself may
                         not be acceptable for others, so adding logic here
     2006-01-05, ---rgf, added subfunction "loadClass" which uses Thread.currentThread().getSystemContextLoader()
                         to load Java classes by name (hint from Rick, thanks an awful lot!!); pre-registering
                         java.lang.Thread in the registry
     2005-11-28, ---rgf, changed license to Apache 2.0
     2005-11-06, ---rgf, added a TypeConvertor to indicate that converstion from "java.lang.String"
                         "java.lang.Object" is o.k. for Rexx (otherwise an error occurs)
     2005-07-30, ---rgf, added method pp() - "pretty print for debug-output"
     2005-07-07, ---rgf, fixed bug in coercing boolean/Boolean values
     2005-06-18, ---rgf, fixed bug if interface is sought and type is String
     2005-06-10, ---rgf, sending attribute message to interface class now works
     2005-05-06, ---rgf, added GET_FIELD_STRICT
 */


class RexxAndJava {

// TODO: rgf, 2016-12-03, remove after debugging
final static boolean bDebugRefCounter=false; // true; // false;
static int bDebugRefCounterThreshold = 1; //  3;   // 2 ;  // > threshold show specific debug infos
final static public ConcurrentHashMap<String,RAJBean> rajRegistryToWatch=new ConcurrentHashMap<String,RAJBean>();



    /** Stores the Java runtime version as an int, where Java 1.6 gets stored as 6 and so on.
    *
    * @since BSF4ooRexx 6.0 (2018-01-05)
    */
    static final int javaRuntimeVersion;

    /** Version string indicating version of this class (majorVersion*100+minorVersion
     *  concatenated with a dot and the sorted date of last change.
     */
    static final public String version = "850.20250827";

    static final private String pkgName = "org.rexxla.bsf.engines.rexx";

    /** If set to <code>.false</code>, then subfunction &quot;EXIT&quot; is not carried out.
        This may be necessary in rare cases, e.g. if BSF4ooRexx programs using <code>bsf.exit</code>
        are run via a BSF4ooRexx application like &quot;ooRexxTry.rxj&quot;, which would be
        shut down together with Java, no questions asked, which may surprise the user.
     * @since 2011-02-09
    */
    static public boolean carryOutSystemExit = true;


    /** Defines the version string. */
    static final private String RAJ_VERSION = version + " " + pkgName + " (org.apache.bsf)";

    // 850: use distinguished name from 641 version ("BSF4ooRexx"), also distinguish from 32-bit
    /** Defines the name of DLL to be used to resolve the native functions. */
    static protected String DLL_NAME = "BSF4ooRexx850"; // default name

    /** Defines the string to indicate an 'eventText' is passed in: &quot;&lt;eventText&gt;&quot;. */
    static final protected String EVENT_TEXT = "<eventText>";

    /** Defines the string that leads in the BSFRegistry key to the Object array containing the
     *  event object and additional information. */
    static final protected String EVENT_LISTENER_ARGUMENTS_LEADIN  = "/*BSFBEAN/*";

    /** Defines the string that leads out the BSFRegistry key to the Object array containing the
     *  event object and additional information. This concludes a sequence which represents
     *  at the same time a nested Rexx comment.
     */
    static final protected String EVENT_LISTENER_ARGUMENTS_LEADOUT = "*/*/";


    /** Defines the string which represents <code>null</code>, by default
        <code>&quot;.NIL&quot;</code>. Arguments given by Rexx can in addition
        be indicated to be <code>null</code> by merely omitting them on the Rexx side.
      */
    static protected String null4Rexx = ".NIL";


    /** Determines whether the return value to Rexx will prepend the string &quot;OBJECT&quot;
     * or &quot;STRING&quot; with a trailing tabulator character (&quot;09&quot;x in Rexx or
     * the '\t' character in Java). By default this is set to <code>false</code> to remain
     * backwardly compatible with older BSF4ooRexx programs.
     */
    // static protected boolean bsfPrefixReturnValue = false; // 2008-06-22
    protected boolean bsfPrefixReturnValue = false; // 2008-06-22
        // the following strings must not be changed as BSF.CLS' BSF.WRAP() routine and
        // other methods and routines there depend on the value *and* length (must be 3)!
    static final protected String OBJECT_INDICATOR_PREFIX="<O>"; // "OBJECT ";
    static final protected String STRING_INDICATOR_PREFIX="<S>"; // "STRING ";


    /** Allows Synchronized access to the vector storing the
      * text sent by the eventListeners.
      */
    protected SyncPutGet eventTextList=new SyncPutGet() ;


    // ---rgf, 2006-11-19
    /** Stores the &quot;netrexx.lang.Rexx&quot; class object, if available.
     *  Cf. <a href="http://www2.hursley.ibm.com/netrexx/">http://www2.hursley.ibm.com/netrexx/</a>.
     */
    static protected Class nlR_class =null;     // to store the class object for 'netrexx.lang.Rexx'
    static protected Method nlR_toString=null;  // to store java.lang.reflect.Method for getting Java
                                                // String value from NetRexx object

    /** Controls whether a deprecation warning was given for using the deprecated *PROPERTY* subfunction.
     * @since 2018-02-17, rgf
     */
    boolean propertyDeprecationWarningAlreadyGiven=false;        // rgf, 2018-02-17

    /** Controls whether a deprecation warning was given for using the deprecated *EVENT* subfunction.
     * @since 2018-02-17, rgf
     */
    boolean eventDeprecationWarningAlreadyGiven=false;


    /** Stores the BSF manager. */
    BSFManager mgr;

    /** Stores the Rexx engine. */
    RexxEngine rexxEngine;

    /** Getter method for field {@link #rexxEngine}. */
    protected RexxEngine getRexxEngine()     // accessor
    {
        return rexxEngine;
    }

    /** As ooRexx 5.0 allows to add command handlers at runtime simplify access to {@link RexxConfiguration}.
     * @since 850 (2022-08-20)
    */
    protected RexxConfiguration getRexxConfiguration()
    {
        return rexxEngine.getRexxConfiguration();
    }

    /**
      * To store the default TypeConvertorRegistry, if needed.
      */
// rgf, 2016-11-27: moved to static
    static TypeConvertorRegistry glob_tcr = new TypeConvertorRegistry();  // will include default set of type convertors


    /** Contains the RexxInterpreter instance ID this engine is associated with.
     */
    private String rii_ID=null;


    /** Getter method.
     *  @return the RexxInterpreter instance ID
     */
    // protected String get_rii_ID(); the BSF.CLS prolog code makes sure that this gets invoked
    public String get_rii_ID()
    {
        return rii_ID;
    }

    /** Setter method. Only meant to be used by Java4Rexx.java and RexxAndJava instance that has no
     *  peer Rexx interpreter instance yet. If already set an exception gets raised.
     *
     */
    protected void set_rii_ID(String new_rii_ID) throws BSFException
    {
        final boolean bDebug= // true;
                              false;

if (bDebug) System.err.println(this+".set_rii_ID(new_rii_ID=["+new_rii_ID+"])");

        if (rii_ID!=null)   // already created for this RAJO!
        {
            throw new BSFException("A Rexx interpreter instance has been created already having the ID ["+rii_ID+"]");
        }

        this.rii_ID=new_rii_ID;

        // create a PhantomReference such that the Rexx interpreter instance can be terminated once
        // the RexxAndJava object gets garbage collected
        new RexxCleanupRef(this, RexxCleanupRef.RefKind.REXX_ENGINE, this.rii_ID);
    }


    /** If terminate() was invoked, then this instance's BSFManager and BSFEngine must not be used anymore.
     */
    protected boolean bTerminated=false;


    /** This serves as a central registry (string-index -> Java object) for all Rexx interpreter instances.
     */
    static private ConcurrentHashMap<String,RAJBean> rajRegistry=new ConcurrentHashMap<String,RAJBean>();
    // static private ConcurrentHashMap<String,RAJBean> rajRegistry=new ConcurrentHashMap<String,RAJBean>(5000);

// ---rgf 2022-07-20: since using ConcurrentHashMap() there is no need to synchronize anymore
//    /** Lock used when adding, removing Java objects or changing their reference counters. */
//    final static private Object lockRajRegistry=new Object();


    /** Field used, if System.identityHashCode() returns duplicate values in method
     *  {@link #makeBeanName(RexxAndJava rajo, Object o)}, to allow adding a unique number to make the
     *  resulting identifying string unique.
     *
     * @since 2012-11-01
     */
    static int spilloverCounter=0;


    /** Load the DLL, which allows interfacing Java with Rexx or Object Rexx, determines
     *  whether setting accessibility rights is supported.
     * <p>
     *
     * Preregisters the most important class objects including primitive and their wrapper classes.
     * Referring to them is possible by using the following strings from Rexx (here the case *is* significant!):
     *
     *  <ul>
     *      <li> &quot;Class.class&quot;,
     *      <li> &quot;Object.class&quot;,
     *      <li> &quot;Method.class&quot;,
     *
     *      <li> &quot;Array.class&quot;,
     *      <li> &quot;String.class&quot;,
     *      <li> &quot;System.class&quot;,
     *      <li> &quot;Thread.class&quot;,
     *
     *      <li> &quot;Boolean.class&quot;,
     *      <li> &quot;boolean.class&quot;,
     *      <li> &quot;Byte.class&quot;,
     *      <li> &quot;byte.class&quot;,
     *      <li> &quot;Character.class&quot;,
     *      <li> &quot;char.class&quot;,
     *      <li> &quot;Double.class&quot;,
     *      <li> &quot;double.class&quot;,
     *      <li> &quot;Integer.class&quot;,
     *      <li> &quot;int.class&quot;,
     *      <li> &quot;Long.class&quot;,
     *      <li> &quot;long.class&quot;,
     *      <li> &quot;Float.class&quot;,
     *      <li> &quot;float.class&quot;,
     *      <li> &quot;Short.class&quot;,
     *      <li> &quot;short.class&quot;,
     *      <li> &quot;Void.class&quot;,
     *      <li> &quot;void.class&quot;.
     *  </ul>
     */
    static {

            // preregister important classes with a predefined bean name in the new central registry
        rajRegistry.put("Class.class",    new RAJBean("Class.class",    Class.class    ));
        rajRegistry.put("Object.class",   new RAJBean("Object.class",   Object.class   ));
        rajRegistry.put("Method.class",   new RAJBean("Method.class",   Method.class   ));

        rajRegistry.put("Array.class",    new RAJBean("Array.class",    Array.class    ));
        rajRegistry.put("String.class",   new RAJBean("String.class",   String.class   ));
        rajRegistry.put("System.class",   new RAJBean("System.class",   System.class   ));
        rajRegistry.put("Thread.class",   new RAJBean("Thread.class",   Thread.class   ));

        rajRegistry.put("Boolean.class",  new RAJBean("Boolean.class",  Boolean.class  ));
        rajRegistry.put("boolean.class",  new RAJBean("boolean.class",  boolean.class  ));
        rajRegistry.put("Byte.class",     new RAJBean("Byte.class",     Byte.class     ));
        rajRegistry.put("byte.class",     new RAJBean("byte.class",     byte.class     ));
        rajRegistry.put("char.class",     new RAJBean("char.class",     char.class     ));
        rajRegistry.put("Character.class",new RAJBean("Character.class",Character.class));
        rajRegistry.put("Double.class",   new RAJBean("Double.class",   Double.class   ));
        rajRegistry.put("double.class",   new RAJBean("double.class",   double.class   ));
        rajRegistry.put("Float.class",    new RAJBean("Float.class",    Float.class    ));
        rajRegistry.put("float.class",    new RAJBean("float.class",    float.class    ));
        rajRegistry.put("int.class",      new RAJBean("int.class",      int.class      ));
        rajRegistry.put("Integer.class",  new RAJBean("Integer.class",  Integer.class  ));
        rajRegistry.put("Long.class",     new RAJBean("Long.class",     Long.class     ));
        rajRegistry.put("long.class",     new RAJBean("long.class",     long.class     ));
        rajRegistry.put("Short.class",    new RAJBean("Short.class",    Short.class    ));
        rajRegistry.put("short.class",    new RAJBean("short.class",    short.class    ));
        rajRegistry.put("Void.class",     new RAJBean("Void.class",     Void.class     ));
        rajRegistry.put("void.class",     new RAJBean("void.class",     void.class     ));



        // ---rgf, 2006-11-19, try to load class "netrexx.lang.Rexx", if available to the contextClassLoader
        try
        {
            nlR_class = Thread.currentThread().getContextClassLoader().loadClass("netrexx.lang.Rexx");
            nlR_toString=nlR_class.getMethod("toString", (Class[]) null);     // get NetRexx toString() Method object
        }
        catch (Exception e)
        {
            try {
                // uses defined class loader of current class
                nlR_class = Class.forName("netrexx.lang.Rexx");
                nlR_toString=nlR_class.getMethod("toString", (Class[]) null);     // get NetRexx toString() Method object
            }
            catch (Exception e0){
                ;
            }
        }

        // 2012-03-12, rgf: move loading the BSF4ooRexx library *after* loading the NetRexx class, this
        //                  way it is clear whether netrexx.lang.Rexx is available for BSF4ooRexx

        // 2020-08-21, rgf: on Linux Java will not honor "/usr/local/lib", so try to load from there explicitly
        //                  cf. <https://bugs.openjdk.java.net/browse/JDK-8073067>

        boolean bLoadSuccessful=false;
        try
        {
            System.loadLibrary( DLL_NAME ); // uses Java's library search order (java.library.path)
            bLoadSuccessful=true;
        }
        catch (UnsatisfiedLinkError t)  // not found via java.library.path
        {
            // 2020-08-21, rgf: if on Linux, explicitly try to load from "/usr/local/lib"
            // as loadLibrary seems to not honor that location, although one is supposed
            // to install non-system shared objects there
            String libFileName=System.mapLibraryName( DLL_NAME );
            if (libFileName.startsWith("lib") && libFileName.endsWith(".so") )  // we are on Linux, check /usr/local/lib
            {
                String strFullLibPath="/usr/local/lib/"+libFileName;
                File fileLibPath=new File(strFullLibPath);

                if (fileLibPath.exists())   // if file exists, we let Java resolve it (e.g. if a symbolic link)
                {
                    try
                    {
                       String canonicalLibPath=fileLibPath.getCanonicalPath();
                       System.load(canonicalLibPath);   // now explicitly load it
// System.err.println("**DEBUG** RexxAndJava.java, # 860; explicitly loading from ["+strFullLibPath+"], canonical=["+canonicalLibPath+"], was successful!");
                       bLoadSuccessful=true;            // indicate we could load/find it!
                    }
                    catch (Throwable t2)    // do nothing
                    {}
                }
            }
        }

        if (!bLoadSuccessful)   // loading was not successful, load again, but do not catch the error anymore
        {
            System.loadLibrary( DLL_NAME );
        }


        // for conversions of java.lang.String -> java.lang.Object, RexxAndJava.java needs an explicit
        // type convertor; rgf, 2005-11-06
        {
// rgf, 2016-11-27: moved to static
                // register conversion of java.lang.String->java.lang.Object here, no need seen
                // to enclose it into the standard type convertors in class TypeConvertorRegistry.java
             TypeConvertor tc = new TypeConvertor () {
              public Object convert (Class from, Class to, Object obj) {
                  return obj;
              }

              public String getCodeGenString() {
                    return "(Class from, Class to, Object obj) {\n" +
                               "return obj;\n" +
                               "}";
              }
            };
                 // register this type-convertor
            glob_tcr.register (String.class, Object.class, tc); // rgf, 2005-07-30
        }


            // 20180105, rgf: determine Java runtime version in use
        int jVersion=6;     // default to Java 6, which as of 2018-02-22 is the baseline Java version
        try {
            String[] st=System.getProperty("java.specification.version").split("\\.");
            jVersion=Integer.valueOf((st[0].equals("1") ? st[1] : st[0]));   // extract and assign Java version
        }
        catch (Throwable t) {}
        javaRuntimeVersion=jVersion;

    }   // end of static block


    /** Returns an unmodifiable version of the {@link #rajRegistry} Map (for debugging purposes).
     * @return unmodifiable version of the registry
    */
    protected static Map<String,RAJBean> getRajRegistry()
    {
        return Collections.unmodifiableMap(rajRegistry);
    }


    /* Allows to refer to the RexxResolve class that gets employed (depends on the version of Java).
    *
    * @since BSF4ooRexx 6.0 (2018-01-05)
    */
    RexxReflectInterface rxReflector=null;


    /** Creates a new {@link RexxReflectInterface} object that is capable of serving the supplied Java version
     *  and which will be used for this instance from now on. This allows changing the {@link RexxReflectInterface} object
     *  for testing purposes, e.g. setting to Java 1.6/6 resolution on a Java 9 runtime. Illegal values will be ignored, ie.
     *  set to {@link RexxReflectJava6}.
     *
     * @param javaVersion indicates the reflective support to use from now on for this instance
     *
     */
    void createRexxReflectJava(int javaVersion)
    {
        RexxReflectInterface oldReflector=rxReflector;  // in case we are already using one

        Class<?> rrjClz=null;
        String rrjClassName="org.rexxla.bsf.engines.rexx.RexxReflectJava";

            // determine reflection class to use
        if (javaVersion<=6 || javaRuntimeVersion==6)    // uses plain java.lang.reflect; Java 1.6/6 has no java.lang.invoke
        {
            rrjClassName=rrjClassName +"6";
        }

            // for Java 7 runtime: assuming default value supplied by RexxAndJava(...) constructor; therefore
            // use RexxReflectJava6, reason: Java 7 does not always have ancestors for inaccessible types in
            // cases where java.lang.reflect works, hence making sure that BSF4ooRexx deployments on Java 7
            // use the known working java.lang.reflect infrastructure only
        else if (javaVersion==7 && javaRuntimeVersion==javaVersion)
        {
            rrjClassName=rrjClassName +"6";
        }

        else if (javaRuntimeVersion>=javaVersion)       // desired version at least the level of the Java runtime version?
        {
            if (javaVersion>6)                          // supplying a javaVersion>7 on Java 7 runtime would allow using
            {                                           // RexxReflectJava7
                rrjClassName=rrjClassName + "7";
            }
            else                                        // supplying a javaVersion<7 on Java 7 or higher would allow using
            {                                           // RexxReflectJava6
                rrjClassName=rrjClassName + "6";
            }
        }

        else                                            // unknown Java version, default to safe java.lang.reflect
        {
            rrjClassName=rrjClassName +"6";
        }


// TODO: remove, forcing RRJ6 to be used and tested
// rrjClassName="org.rexxla.bsf.engines.rexx.RexxReflectJava6";

        // now reflectively load and instantiate the RexxReflectJavaX class and cast object to rxReflect
        try {
                ClassLoader cl=Thread.currentThread().getContextClassLoader();  // try the Thread's context loader first
                if (cl!=null)   // if set, use it
                {
                    try
                    {
                        rrjClz=cl.loadClass(rrjClassName);
                    }
                    catch (ClassNotFoundException e) {}
                }

                if (cl==null || rrjClz==null)     // not found yet, last try using this class ClassLoader
                {
                    rrjClz=RexxAndJava.class.getClassLoader().loadClass(rrjClassName);
                }

                Constructor rrjConstr=rrjClz.getDeclaredConstructor(new Class[]{int.class} );     // get default constructor

                rxReflector=(RexxReflectInterface) rrjConstr.newInstance(new Object[]{javaVersion});

                if (oldReflector!=null && oldReflector.isPublicLookup())  // o.k. we reflect this also for the new reflector to not allow
                {
                    rxReflector.setPublicLookup();  // make sure that new object is also restricted to publicLookup!
                }
            }
            catch (Throwable t)
            {
                String info="RexxAndJava(): panic! Cannot load and instantiate class \""+rrjClassName+"\", Throwable: "+t;
                System.err.println(info);
                throw new RuntimeException(info,t);
            }
    }

    /** Constructor to receive and store the BSF manager and the Rexx engine.
     */
    RexxAndJava (BSFManager mgr, RexxEngine rengine)
    {
        this.mgr        = mgr;     //the current BSFManager
        this.rexxEngine = rengine; //the current RexxEngine
        jniSetupNativeJVMPointer();     // make sure the JNI library can initialize the Java related datastructures

        // create and assign a rxReflector
        createRexxReflectJava(javaRuntimeVersion);

        // rii_ID cannot be set at this time, but after a peer Rexx interpreter instance got created
        // cf. set_rii_ID(...) above
    }




    /** This native method makes sure that the C++ library gets a hold to
     *  this JVM in case it does not already have a pointer to it.
     */
    protected native void jniSetupNativeJVMPointer ();     // changed 2012-02-06, rgf



    /** This native method Calls the Rexx interpreter,
      * having it execute the passed in
      * <em>script</em> with the given array of arguments.
      *
      * @param scriptSourceLocation a String denoting the location from where the
      *               script code comes from (usually a fully qualified file name)
      *               or <code>null</code>, if no information is available
      *
      * @param script a String consisting of Rexx statements separated by
      *               by line-end characters (';' or CR-LF).
      *
      * @param args an array of Strings representing the arguments
      *               or <code>null</code>, if no arguments are available.
      *
      * @return a String containing the result or <code>null</code>, if
      *         no result is returned or the Rexx interpreter stopped
      *         execution due to a runtime error.
      */

// rgf, 2009-05-24: no need anymore; also this was restricted to accepting arguments in String[] form
//                  and returning a String only, whereas the replacements jniRexxRunProgram() and
//                  jniRexxSendMessageToRexxObject() accept Object[] arguments and return Object
//
//    public native String jniRexxStart (String scriptSourceLocation, String script, String[] args);



    /** This native method waits for the Object Rexx interpreter to terminate and waits until
      * all of the cleanup (e.g. of Object Rexx) is done. This is necessary for ooRexx 3.x.
      *
      * @return returns always 0. (Just there to allow future return codes, if necessary.)
    @deprecated
      */
    @Deprecated protected native int jniRexxWaitForTermination ( );

    /** This native method indicates whether the Object Rexx interpreter is still running or not.
      * This is necessary for ooRexx 3.x.
      *
      * @return returns always 0. (Just there to allow future return codes, if necessary.)
    @deprecated
      */
    @Deprecated protected native int jniRexxDidRexxTerminate ( );


    /** This native method returns the current thread id as seen by
     *  BSF4ooRexx encoded as a decimal value into a String. This value
     *  can be used as an argument for {@link #jniRexxSetHalt(String tid)}.
      *
      * @return returns the decimal value of the thread id (TID)
      */
    protected native String jniRexxGetTID ( );



    /** This native method halts a Rexx interpreter instance or individual
     *  Rexx threads in the current process. It uses the Rexx function
     * &quot;RexxSetHalt()&quot; (cf. the documentation in the &quot;rexxpg.pdf&quot;
     * book of Object REXX or ooRexx.
     *
     * @param tid a string containing either the thread id as returned by
     *            {@link #jniRexxGetTID ( )} or the string <code>;&quot;0&quot;</code>,
     *            which causes the Rexx interpreter instance to halt (terminate) all
     *            its Rexx threads by raising the Rexx halt condition.
      *
      * @return returns the return code of the Rexx function (from the ooRexx
     *          documentation, rev. 4334):
     *           <table>
     *              <tr>
     *                 <td><code>0</code>
     *                 <td><code>RXARI_OK</code>
     *                 <td>The function completed successfully.
     *
     *              <tr>
     *                 <td><code>1</code>
     *                 <td><code>RXARI_NOT_FOUND</code>
     *                 <td>The target Rexx procedure was not found.
     *
     *              <tr>
     *                 <td><code>2</code>
     *                 <td><code>RXARI_PROCESSING_ERROR</code>
     *                 <td>A failure in Rexx processing occurred.
     *
     *           </table>
      */
    // used by RexxEngine
    protected native int jniRexxSetHalt (String tid);


    // rgf, 2009-05-03, exploiting new ooRexx 4.0 APIs ----------------------------------------
    /** Creates a new Rexx interpreter instance using the ooRexx 4.0 API <code>RexxCreateInterpreter()</code>.
     *
     * @return a String representing the created Rexx interpreter instance ID or <code>null</code>, if
     *         no Rexx interpreter instance could be created
     *
     * @since May 2009
     */
    protected native String jniRexxCreateInterpreterInstance (Object [] options);           // RexxCreateInterpreter(), returns rii-id



    // rgf, 2009-05-26, exploiting new ooRexx 4.0 APIs ----------------------------------------
    /** Returns the Rexx interpreter instance serving as the root of the linked list of Rexx interpreter using the ooRexx 4.0 API <code>RexxCreateInterpreter()</code>.
     * This will be needed in the context where Rexx loads Java, and the Java side needs to set up the BSF infrastructure
     * accordingly.
     *
     * @return a String representing the root Rexx interpreter instance ID or <code>null</code>, if
     *         no Rexx interpreter instance is available at all
     *
     * @since May 2009
     */
    protected native String jniGetRexxInterpreterInstanceRoot ();           // RexxCreateInterpreter(), returns rii-id



        // execute piece of code or dispatch method on ooRexx object
    /** Uses the ooRexx 4.0 API to execute a Rexx program or to execute a callback (sending a message to a given object).
     *
     * @param rii_ID a String representing the Rexx interpreter instance as returned by {@link #jniRexxCreateInterpreterInstance ()}
     * @param invocationType determines the desired invocation
     *                  <dl>
     *                       <dt>1 <dd> execute Rexx program from file, use the 4.0 API <code>CallProgram</code>
     *                       <dt>2 <dd> execute Rexx program from buffer, uses the 4.0 API <code>NewRoutine</code> and <code>CallRoutine</code>
     *                       <dt>3 <dd> load Rexx package (and run prolog) from file, use the 4.0 API <code>LoadPackage</code>
     *                       <dt>4 <dd> load Rexx package (and run prolog) from buffer, use the 4.0 API <code>LoadPackageFromData</code>
     *                  </dl>
     *
     * @param fileName  name (path) to file that contains the program to execute
     * @param programData Rexx code to execute
     * @param args an array of arguments to pass on
     *
     * @throws a {@link RexxException}, if the argument does not denote an existing Rexx interpreter instance
     * @return a return value from running the Rexx program or <code>null</code>
     *
     * @since May 2009
     */
    protected  native Object jniRexxRunProgram (
                    String  rii_ID,                 // RexxInstance instance ID
                    int     invocationType,         // determines whether "CallProgram", "LoadPackage" or "LoadPackageFromData" is to be used
                    String  fileName,               // filename which contains the program to run
                    String  programData,            // Rexx code to execute; if given "fileName" denotes a (symbolic) name for this code
                    Object[]args                    // arguments
                                           );
                    // args: of type String (keys to registry or pure values) or
                    //       RexxProxy (JNI needs to fetch and use it)


    /** Uses the ooRexx 4.0 API to execute a Rexx program or to execute a callback (sending a message to a given object).
     *
     * @param rii_ID a String representing the Rexx interpreter instance as returned by {@link #jniRexxCreateInterpreterInstance ()}
     * @param obj_ID the object id that is used as a key on the JNI side, {@link org.rexxla.bsf.engines.rexx.RexxProxy#getRexxObjectID ()}
     * @param userData_ID optional RexxProxy, supplied either with the <code>BsfCreateRexxProxy()</code> as second argument or later
     *                    set by programs
     *
     * @param javaObjectBean  the Java object that invoked this very callback
     * @param methodObjectBean  <code>java.lang.reflect.Method</code> object that was invoked in the Java proxy
     * @param messageName the name of the message to send to the Rexx object (the Rexx object will look for a method
     *               named like the message and invoke it)
     * @param methodDescription string formated as internal Java string that describes a method's arguments and return value
     * @param args an array of arguments to pass on
     * @param returnType the primitive type signature (for primitive types or matching wrapper classes) or <code>null</code> for any object
     * @throws a {@link RexxException}, if the argument does not denote an existing Rexx interpreter instance
     *
     * @return <code>0</code>
     *
     * @since May 2009
     */
    protected native Object jniRexxSendMessageToRexxObject (
                    String  rii_ID,             // RexxInstance instance ID
                    String  obj_ID,             // RexxProxy objectID
                    String  userData_ID,        // RexxProxy userData_ID
//                    String  creationTID,      // the BsfGetTID() value of the thread in which the proxy got created
                    String  javaObjectBean,     // javaObjectBean (a String)
                    String  methodObjectBean,   // methodObjectBean (a String)
                    String  messageName,        // message name (determines name of method to invoke)
                    String  methodDescription,  // messageDesscription, internal string describing arguments and return value
                    Object[]args,               // arguments, edited for native layer
                    String  returnType,         // primitive type signature or null
                    String  scope_obj_ID        // a String or RexxProxy objectID denoting scope (superclass) to start resolving method
                                                           );
                    // args: of type String (keys to registry or pure values) or
                    //       RexxProxy (JNI needs to fetch and use it)



    /** Unregisters the Rexx object denoted by 'obj_ID' from the JNI registry.
     *
     * @param obj_ID the object id that is used as a key on the JNI side
     *
     * @return number of references to the Rexx object in the JNI registry left; a
     *         number of '0' indicates that no references are left, a return value of '-1'
     *         indicates that the Rexx object was not registered (could not be found)
     */
    // used by RexxProxy
    protected native int jniUnregisterRexxObject(String obj_ID);


    /** Uses the ooRexx 4.0 API <code>Halt()</code> to raise the <code>HALT</code> condition in all Rexx threads
     *  belonging to the given Rexx interpreter instance.
     *
     * @param rii_ID a String representing the Rexx interpreter instance as returned by {@link #jniRexxCreateInterpreterInstance ()}
     * @throws a {@link RexxException}, if the argument does not denote an existing Rexx interpreter instance
     * @return <code>0</code>
     *
     * @since May 2009
     */
    // used by RexxEngine
    protected native int    jniRexxHaltInterpreterInstance (String rii_ID); // use Halt()


    /** Uses the ooRexx 4.0 API <code>Terminate()</code> to wait on all Rexx threads
     *  belonging to the given Rexx interpreter instance to terminate.
     *
     * @param rii_ID a String representing the Rexx interpreter instance as returned by {@link #jniRexxCreateInterpreterInstance ()}
     * @throws a {@link RexxException}, if the argument does not denote an existing Rexx interpreter instance
     * @return <code>0</code>
     *
     * @since May 2009
     */
    // used by RexxEngine and Java4Rexx
    protected native int    jniRexxTerminateInterpreterInstance (String rii_ID); // use Terminate(), but *must* be issued from the original thread context


     // ------------------ JNI functions meant to be accessed by Java exit handlers only!
    //                     (these jni functions need a properly set up opaque slot argument!)

     //  rgf, 2012-02-08, used for allowing exit and command handlers to interact with their RexxExitContext
     //                   for raising conditions and querying/setting variables.
     //
     protected native void    jniRaiseCondition    (Object[] slot, String conditionName, String description, Object[] additional, Object result);
     protected native void    jniRaiseException    (Object[] slot, long definedErrorNumber, Object[] substitutions);
     protected native void    jniRaiseException0   (Object[] slot, long definedErrorNumber);
     protected native void    jniRaiseException1   (Object[] slot, long definedErrorNumber, String substitution1);
     protected native void    jniRaiseException2   (Object[] slot, long definedErrorNumber, String substitution1, String substitution2);
     protected native Object  jniGetContextVariable(Object[] slot, String variableName);
     protected native void    jniSetContextVariable(Object[] slot, String variableName, Object variableValue);

     // rgf, 2012-02-11: for RexxHandler access only (these jni functions need a properly set up opaque slot argument!)
     protected native boolean jniCheckCondition    (Object[] slot);
     protected native void    jniClearCondition    (Object[] slot);
     protected native Object  jniGetConditionInfo  (Object[] slot);

     protected native void    jniSetThreadTrace    (Object[] slot, boolean state);
     protected native void    jniHaltThread        (Object[] slot);

     // rgf, 2012-02-12: for RexxHandler access only (these jni functions need a properly set up opaque slot argument!)
     protected native void    jniDropContextVariable(Object[] slot, String variableName);

     // rgf, 2012-02-18: for RexxHandler access only (these jni functions need a properly set up opaque slot argument!)
     protected native void    jniSetContextVariableToNil(Object[] slot, String variableName);

     // rgf, 2012-02-19: for RexxHandler access only (these jni functions need a properly set up opaque slot argument!)
     protected native Object  jniGetCallerContext   (Object[] slot);
     protected native Object  jniGetAllContextVariables(Object[] slot);

     // rgf, 2012-02-24: for RexxHandler access only (these jni functions need a properly set up opaque slot argument!)
     protected native Object  jniGetLocalEnvironment(Object[] slot);
     protected native Object  jniGetGlobalEnvironment(Object[] slot);
     // rgf, 2012-02-25: for RexxHandler access only (these jni functions need a properly set up opaque slot argument!)
     protected native Object  jniNil(Object[] slot);
     protected native long    jniInterpreterVersion(Object[] slot);
     protected native long    jniLanguageLevel     (Object[] slot);

     // rgf, 2014-03-29
     protected native String  jniProcEnvironment(int function, String envName, String envValue);


     // ------------------ allow fetching a few important Rexx objects resp. Rexx interpreter related information
     // rgf, 2015-05-09
     protected native Object  jniGetLocalEnvironment0 (String rii_ID);
     protected native Object  jniGetGlobalEnvironment0(String rii_ID);
     protected native Object  jniNil0                 (String rii_ID);
     protected native long    jniInterpreterVersion0  (String rii_ID);
     protected native long    jniLanguageLevel0       (String rii_ID);

     // rgf, 2018-02-26 --------- for testing and debugging purposes
     protected native void    jniTestPing             ();   // allows Java to call into BSF4ooRexx.cc and to return immediately
     static void              javaTestPing            ()    // allows native code to call into Java and to return immediately (for debugging and testing)
     {
         return;
     }

     // rgf, 2022-08-19 _-------- add support for RexxRedirectingCommandHandler
     // flag: 0=readInput, 1=readInputBuffer
     protected native String jniRCH_Read           (Object[] slot, int flag);
     protected native byte[] jniRCH_ReadAsByteArray(Object[] slot);

     // flag: 0=writeOutput, 1=writeOutputBuffer, 2=errorOutput, 3=errorOutputBuffer
     protected native void   jniRCH_Write(Object[] slot, int flag, String data);
     protected native void   jniRCH_Write(Object[] slot, int flag, byte[] data);

     // rgf, 2022-09-01 ---- add support for RexxHandler to get a new array, directory, stem, stringtable object
     // kind: 0=Array, 1=Directory, 2=Stem, 3=StringTable
     protected native Object  jniCreateCollectionObject  (Object[] slot, int kind, String someString);


    /**  rgf, 2003-01-15, used for allowing the BSF4ooRexx-DLL to get at *env, *obj and then to mid etc.
     * */
    protected native int jniInitialize4Rexx() ;

    /** rgf, 2022-08-05, used to allow fetching the ooRexx 'parse version' string. Note:
     *                   each invocation of this native function will cause a Rexx instance
     *                   to be created, used to run 'parse version v;return v;' and terminate it
     *                   before returning.
     *
     *
    */

    /** Causes the native side to create a new Rexx interpreter instance, run the supplied
     *  rexxCode and the optional single argument string, return value is always a string.
     *  This is meant as a simple tool for Java programmers.
     *
     * @param rexxCode optional, the Rexx code to execute; if null the RII gets created and terminated nevertheless
     * @param rexxArgument optional, single string argument
     * @return the string value of the result or null; or if a Rexx condition was raised while
     *         creating the Rexx routine object or while running the routine, a string with the Rexx
     *         like error message gets returned, led in by the string "BSF4ooRexx/jniExecuteSimpleProcedureOnOwnRII()"
     */
    static protected native String jniExecuteSimpleProcedureOnOwnRII(String rexxCode, String rexxArgument);



    /** Entry point for Rexx calls into Java. This method carries out
      * all the necessary type conversions and finally calls/invokes the
      * indicated Java method.
     *
      * <p>
     *
     * <hr width="50%">
     *
      <em>&quot;typeIndicator&quot;</em>: If a call needs to explicitly indicate the type of Rexx arguments meant
      for invoking a Java
      * method (indicated by a trailing "Strict" in the subfunction name),
      * than the following strings/characters must be used for defining
      * the type of the argument immediately preceding the respective
        argument (minimum letters needed are uppercased and printed in bold):
      *
      *<p>

        <table border="1" cellpadding="3" cellspacing="0" align="center">
        <tr class="TableHeadingColor">
        <td> <strong> TypeIndicator</strong>
        <td> <strong> Following Argument is of Type:
             </strong>

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>BO</strong>olean&quot; </code>
        <td> <code> &quot;boolean&quot;</code> i.e. the value <code>0</code> (false) or <code>1</code> (true)

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>BY</strong>te&quot; </code>
        <td> <code> &quot;byte&quot;</code> a byte value

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>C</strong>har&quot; </code>
        <td> <code> &quot;char&quot;</code> i.e. a single (UTF8) character

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>D</strong>ouble&quot; </code>
        <td> <code> &quot;double&quot;</code> a double value

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>F</strong>loat&quot; </code>
        <td> <code> &quot;float&quot;</code> a float value

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>I</strong>nt&quot; </code>
        <td> <code> &quot;int&quot;</code> an integer value

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>L</strong>ong&quot; </code>
        <td> <code> &quot;long&quot;</code> a long value

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>O</strong>bject&quot; </code>
        <td> &quot;Object&quot; an Object which must be registered already

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>SH</strong>ort&quot; </code>
        <td> <code> &quot;short&quot;</code> a short value

        <tr class="TableRowColor"><!-- table row -->
        <td> <code> &quot;<strong>ST</strong>ring&quot; </code>
        <td> <code> &quot;String&quot;</code> a string value (UTF8)


        </table>
        <p>

      * Hence, for the "...Strict"-subfunctions the Rexx supplied arguments
        must be given
      * in pairs by Rexx: first the type argument (from the above table)
       and then the argument itself.
     * <hr width="50%">
      *
      *  <p>The call syntax from Rexx looks like, e.g.:
      *
      * <pre>
      *    call BSF "SubFunctionName", "argument1", "argument2", "", ...
      * or:
      *    a=BSF("SubFunctionName", "argument1", "argument2", ...)
      * </pre>
      *
      *
      * <p>The following BSF methods are made available to Rexx and
      * can therefore be indicated as the first argument (the 'subfunction') to the 'BSF'
      * call from Rexx:
      * <p>
      *
     *
     *
     *
     *

        <table border="1" cellpadding="3" cellspacing="0">
        <tr class="TableHeadingColor">
        <td> <strong>SubFunctionName </strong>
        <td> <strong> Argument     </strong>
        <td> <strong> Description  </strong>


        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;addEventListener&quot; </code>
        <td colspan="2">Adds an event listener to a bean and defines the <code>eventText</code>
                        to be generated. These generated texts can be retrieved with the
                        function <code>pollEventText</code>.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of a registered bean which should get monitored.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>eventSetName </code>
        <td> Mandatory, name of the set the event belongs to. This name is used
             to create an event adapter at runtime.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>filter </code>
        <td> Mandatory, name of the actual event which should cause a notification.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>eventText </code>
        <td> Mandatory, text which should be sent by this event listener, each
             time the event occurs.




        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;arrayAt&quot; </code>
        <td colspan="2">Allows accessing a Java array element.
                        <br>Returns the Java object at the indicated array element,
                            or <code>null</code>, if no object is stored there.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arrayObject </code>
        <td> Mandatory, name of a registered arrayObject (received by Java).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>idx1 </code>
        <td> Mandatory, integer indicating the position in dimension 1.
             <p>
             <em>Alternatively,</em> a sole Java int-array containing the 0-based index-values.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>idx2 </code>
        <td> Integer indicating the position in dimension 2 ...



        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;arrayLength&quot; </code>
        <td colspan="2">Returns the value of the 'length' field of the <code>arrayObject</code>.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arrayObject </code>
        <td> Mandatory, name of a registered arrayObject (received by Java).





        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;arrayPut&quot; </code>
        <td colspan="2">Allows to put a new value into a Java array element at the
                        indicated position.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arrayObject </code>
        <td> Mandatory, name of a registered arrayObject (received by Java).


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>newValue </code>
        <td> The new value to be set at the indicated position in the array.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>idx1 </code>
        <td> Mandatory, integer indicating the position in dimension 1.
             <p>
             <em>Alternatively,</em> a sole Java int-array containing the 0-based index-values.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>...idxn </code>
        <td> Integer indicating the position in dimension n ...

     *
     *

        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;arrayPutStrict&quot; </code>
        <td colspan="2">Allows to put a new value into a Java array element at the
                        indicated position.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arrayObject </code>
        <td> Mandatory, name of a registered arrayObject (received by Java).


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>typeIndicator </code>
        <td> Type indicator for <code>newValue</code>

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>newValue </code>
        <td> The new value to be set at the indicated position in the array.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>idx1 </code>
        <td> Mandatory, integer indicating the position in dimension 1.
             <p>
             <em>Alternatively,</em> a sole Java int-array containing the 0-based index-values.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>... idxn </code>
        <td> Integer indicating the position in dimension n ...

     *
     *


        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;bsfPrefixReturnValue&quot; </code>
        <td colspan="2">Allows to globally set RexxAndJava to prepend a type hint
                        to the string that gets returned ('&lt;O&gt;' for a Java
                        object in the BSFRegistry where the following string denotes
                        the index value; '&lt;S&gt;' indicates that the remainder is
                        to be interpreted as a plain string)

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>newSetting</code>
        <td> Optional. If omitted the current setting will be returned (&quot;1&quot;
                       or quot;0&quot;).
                       If given, then it must be a boolean value, i.e.  &quot;1&quot; (true)
                       or quot;0&quot; (false).
     *
     *

        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;carryOutSystemExit&quot; </code>
        <td colspan="2">Allows to globally set RexxAndJava to not carry out
     *                  the subfunction <code>&quot;exit&quot;</code>. This
     *                  allows e.g. <code>&quot;ooRexxTry.rxj&quot;</code> to
     *                  run BSF4ooRexx programs that excercise that subfunction.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>newSetting</code>
        <td> Optional. If omitted the current setting will be returned (&quot;1&quot;
                       or quot;0&quot;).
                       If given, then it must be a boolean value, i.e.  &quot;1&quot; (true)
                       or quot;0&quot; (false).
     *


        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;createJavaArray&quot; </code> <br>
     *       <code> &quot;createArray&quot; </code> (deprecated)
        <td colspan="2">Creates a Java array of the given <code>componentType</code> and number of
                       dimensions.
                        <br>Returns the created Java array object.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>componentType</code>
        <td> Mandatory, name of a registered Java class object or a string fully qualifying a Java class.
             For convenience, you may use any of the pre-registered beans named (note case of first letter!):<br>

                 &quot;<code>Class.class</code>&quot;,
                 &quot;<code>Object.class</code>&quot;,
                 &quot;<code>Method.class</code>&quot;,

                 &quot;<code>Array.class</code>&quot;,
                 &quot;<code>String.class</code>&quot;,
                 &quot;<code>System.class</code>&quot;,

                 &quot;<code>Boolean.class</code>&quot;,
                 &quot;<code>boolean.class</code>&quot; (primitive data type),
                 &quot;<code>Byte.class</code>&quot;,
                 &quot;<code>byte.class</code>&quot; (primitive data type),
                 &quot;<code>Character.class</code>&quot;,
                 &quot;<code>char.class</code>&quot; (primitive data type),
                 &quot;<code>Double.class</code>&quot;,
                 &quot;<code>double.class</code>&quot; (primitive data type),
                 &quot;<code>Integer.class</code>&quot;,
                 &quot;<code>int.class</code>&quot; (primitive data type),
                 &quot;<code>Long.class</code>&quot;,
                 &quot;<code>long.class</code>&quot; (primitive data type),
                 &quot;<code>Float.class</code>&quot;,
                 &quot;<code>float.class</code>&quot; (primitive data type),
                 &quot;<code>Short.class</code>&quot;,
                 &quot;<code>short.class</code>&quot; (primitive data type).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>capacity 1</code>
        <td> Mandatory, integer indicating the number of elements in dimension 1.
             <p>
             <em>Alternatively,</em> a sole Java int-array containing the capacity per dimension.
             The first dimension is stored with index 0, the second with index 1, ...

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>capacity 2</code>
        <td> Integer indicating the number of elements in dimension 2.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> ... <code>capacity n </code>
        <td> Integer indicating the number of elements in dimension n.
     *
     *
     *


        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;createJavaArrayOf&quot; </code><br>
     *       <code>&quot;createArrayOf&quot; </code> (deprecated)
     *
        <td colspan="2">Creates a single dimensioned Java array of the given <code>componentType</code> and
     *                  adds the supplied arguments to it. The length (size) is determined by the
     *                  added arguments and can be <code>0</code>, if only the <code>componentType</code>
     *                  was given (an empty Java array object).
                        <br>Returns the created Java array object.

     *
        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>componentType</code>
        <td> Mandatory, name of a registered Java class object or a string fully qualifying a Java class.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arg # 1</code>
        <td> Argument # 1 (if given must be of the given <code>componentType</code>).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>... arg # n</code>
        <td> Argument # n (if given must be of the given <code>componentType</code>).





        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;wrapArray&quot; </code>
        <td colspan="2">Wraps the given array up in a {@link ArrayWrapper}-object, allowing
                        easy access to information about the array like dimensions, size and
                        also getting and setting values in an easy manner.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arrayObject </code>
        <td> Mandatory, name of a registered arrayObject (received by Java).




        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;exit&quot; </code>
        <td colspan="2">Terminates the Java Virtual Machine. Allows Rexx
                        to shut down the JVM (and thereby Rexx as well).
                        In order for Rexx being able to shutdown properly
                        itself, the termination of the JVM is delayed by
                        <code>time2wait</code>.

                        <br>Returns the string
                        <code>&quot;SHUTDOWN,&nbsp;REXX&nbsp;!&quot;</code>.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>retVal</code>
        <td> Optional integer return value. If omitted, then &quot;0&quot;
             will be used as argument for the <code>System.exit(n)</code> call.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>time2wait</code>
        <td> Optional number of milliseconds (msecs) to wait until the JVM will
             be terminated. This allows Rexx to shutdown (clean up) its side as
             well. Default value, if omitted: <code>100</code>, i.e. 100 msecs,
             i.e. 1/10th second.


        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;getBSFManager&quot; </code>
        <td colspan="2">Returns the BSFManager object that dispatches this
                        Rexx engine instance. This way one can get at the
                        version of BSF in use, but also one gains the ability
                        to dispatch scripts in any of the supported BSF languages
                        sharing the BSF registry with this Rexx engine instance!

     *
        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;getFieldValue&quot; </code>
        <td colspan="2">Looks up a <em>public</em> field of the registered
                        object. The case of the characters of the field name does not matter.
                        <br>
                        <em>Hint:</em> If the field cannot be found, then this subfunction assumes that
                        a getter method (field name prepended by &quot;get&quot;) exists for the field and tries to invoke one. If
                        you do not want this behaviour use subfunciton
                        <code>&quot;getFieldValueStrict&quot;</code> instead.


                        <br>Returns the value of the field.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of the object to be looked up.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>fieldName </code>
        <td> Mandatory, name of the <em>public</em> field of the object.



        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;getFieldValueStrict&quot; </code>
        <td colspan="2">Looks up a <em>public</em> field of the registered
                        object. The case of the characters of the field name must match exactly.
                        <br>Returns the value of the field.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of the object to be looked up.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>fieldName </code>
        <td> Mandatory, <em>case sensitive</em> name of the <em>public</em> field of the object.






        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;getPropertyValue&quot; </code> <strong>(untested!)</strong>
        <td colspan="2">Looks up a <em>property</em> of the registered
                        <em>Java Bean</em> object.
                        <br>Returns the value of the property.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of the Java Bean object to be looked up.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>propertyName </code>
        <td> Mandatory, name of the Java Bean <em>property</em>.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>index </code>
        <td> Mandatory, <code>null</code>, if Java Bean property is not indexed,
             a valid integer number else.

     *

        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;getRexxAndJava&quot; </code>, synonym: <code>&quote;getRAJO&quote;</code>
        <td colspan="2">Returns the RexxAndJava object to which this Rexx program
     *                  interfaces.

        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;getRexxEngine&quot; </code>
        <td colspan="2">Returns the RexxEngine object, that is used to run the
     *                  Rexx program.

     *

        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;get_RII_ID&quot; </code>
        <td colspan="2">Returns the &quot;Rexx Interpreter Instance (RII) ID&quot; used to attach
     *                  to the corresponding Rexx interpreter instance


        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;getStaticValue&quot; </code>
        <td colspan="2">Looks up a <em>public static</em> field of the
                        given class or interface. This function does <em>not instantiate</em>
                        the class (would not be possible for abstract classes
                        or interfaces). Case of <code>fieldName</code> is <em>not</em> relevant!
                        <br>Returns the value of the public static field.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>className </code>
        <td> Mandatory, name of the class, abstract class or interface to be looked up.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>fieldName </code>
        <td> Mandatory, name of the <em>public static</em> field of the object.


        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;getStaticValueStrict&quot; </code>
        <td colspan="2">Looks up a <em>public static</em> field of the
                        given class or interface. This function does <em>not instantiate</em>
                        the class (would not be possible for abstract classes
                        or interfaces). Case of <code>fieldName</code> is relevant!
                        <br>Returns the value of the public static field.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>className </code>
        <td> Mandatory, name of the class, abstract class or interface to be looked up.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>fieldName </code>
        <td> Mandatory, <em>case sensitive</em> name of the <em>public static</em> field of the object.


        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;haltThread&quot; </code>
        <td colspan="2">Halts (terminates) the ooRexx thread with the given
                        <code>tid</code>. A <code>tid</code> value of <code>0</code>
                        will cause all ooRexx threads to be halted.

                        <br>Returns the return value of <code>RexxSetHalt(...)</code>:
                            <code>0</code> (o.k.), <code>1</code> (not found), and
                            <code>2</code> (failure).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>tid </code>
        <td> Mandatory, the thread id as returned e.g. by <code>BsfGetTID()</code> or
              <code>0</code> to halt (terminate) all ooRexx threads.





        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;invoke&quot; </code>
        <td colspan="2">Invokes (calls) the method with the given arguments
                        on the bean.
                        <br>

                        <em>Hint:</em> if the method could not be found and has no arguments,
                        this subfunction assumes that the value of a field is sought. Therefore,
                        it employs the subfunction <code>&quot;getFieldValue&quot;</code> using
                        the <code>methodName</code> as the <code>fieldName</code>.

                        If you do not want to use this
                        feature, then employ the subfunction <code>&quot;invokeStrict&quot;</code> instead.

                        <br>Returns the result of the method invocation or
                            <code>null</code>.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of a registered bean on which the method (function)
             should get invoked.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>methodName </code>
        <td> Mandatory, name of the method which should get invoked. <code>methodName</code> is <em>not</em>
             case sensitive!

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arg # 1</code>
        <td> Argument # 1 (if given).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>... arg # n</code>
        <td> Argument # n (if given).






        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;invokeStrict&quot; </code>
        <td colspan="2">Invokes (calls) the method with the given arguments
                        on the bean.
                        The case of the characters of the method name must match exactly.
                        Each Rexx argument <em>must</em> be preceeded by its Java type.

                        <br>Returns the result of the method invocation or
                            <code>null</code>.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of a registered bean on which the method (function)
             should get invoked.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>methodName </code>
        <td> Mandatory, <em>case sensitive</em> name of the method which should get invoked.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>typeIndicator # 1</code>
        <td> Type indicator for argument # 1 (if given).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arg # 1</code>
        <td> The argument # 1 itself (if given).

        <tr class="TableRowColor"><!-- table row -->
        <td >
        <td colspan="2"> <em>Any additional arguments must be given in pairs of
                       &quot;typeIndicator&quot; and &quot;arg&quot; as well.</em>




        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;isA&quot; </code>
        <td colspan="2">Tests whether <code>javaObject</code> is an instance
                        of <code>javaClass</code> (equivalent to Java's <code>instanceof</code> operator).

                        <br>returns <code>.true</code> (<code>1</code>) or
                                    <code>.false</code> (<code>0</code>), respectively

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>javaObject </code>
        <td> Mandatory, Java object to test.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>javaClass </code>
        <td> Mandatory, Java class object or a string fully denoting a Java class.



        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;loadClass&quot; </code>
        <td colspan="2">Loads a Java class with the given name.
            <br>Returns the object or <code>null</code>, if not found.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, fully qualified name of the Java class to be looked.
             Returns the class object rendered to a string or <code>null</code>, if not found.




        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;lookupBean&quot; </code>
        <td colspan="2">Looks up an object in the BSF
            manager object registry. (Allows for retrieving pre-<em>declared
            beans</em> as well.)
            <br>Returns the object or <code>null</code>, if not found.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of the object to be looked up. Returns
             the object rendered to a string or <code>null</code>, if not found.



        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;new&quot;</code> or<br>
             <code>&quot;registerBean&quot;</code> (a synonym)
        <td colspan="2">Creates a new object (instantiating the given Java class
                        with the given arguments) and registers it using the
                        given <em>beanName</em>.
                        <br>Returns <em>beanName</em>
                        (always use this returned beanName for looking up the
                        object in the registry).


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Name of the object to be created and registered.
             if no name is given (empty string or <code>null</code>)
             then a unique one will be created and returned;
             this is done in method {@link #makeBeanName(RexxAndJava rajo, Object o)}.


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanType</code>
        <td> Mandatory, type (Java class name) of the bean (Java object) to be
             created and registered.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arg # 1</code>
        <td> The argument # 1 (if given).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>... arg # n</code>
        <td> The argument # n (if given).





        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;newStrict&quot; </code>  or<br>
             <code>&quot;registerBeanStrict&quot;</code> (a synonym)
        <td colspan="2">Creates a new object (instantiating the given Java class
                        with the given arguments) and registers it using the
                        given <em>beanName</em>.
                        <br>Returns <em>beanName</em>
                        (always use this returned beanName for looking up the
                        object in the registry).


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Name of the object to be created and registered.
             if no name is given (empty string or <code>null</code>)
             then a unique one will be created and returned;
             this is done in method {@link #makeBeanName(RexxAndJava rajo, Object o)}.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanType</code>
        <td> Mandatory, type (Java class name) of the bean (Java object) to be
             created and registered.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>typeIndicator # 1</code>
        <td> Type indicator for argument # 1 (if given).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arg # 1</code>
        <td> The argument # 1 (if given).

        <tr class="TableRowColor"><!-- table row -->
        <td >
        <td colspan="2"> <em>Any additional arguments must be given in pairs of
                       &quot;typeIndicator&quot; and &quot;arg&quot; as well.</em>







        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;pollEventText&quot; </code>
        <td colspan="2">Polls for the eventText defined in the above subfunction
                        &quot;<code>addEventListener</code>&quot; placed
                        into a queue by the appropriate event listeners,
                        or posted via &quot;<code>postEventText</code>&quot; below.
                        <br>

                        If no timeout value is supplied, &quot;0&quot;
                        will be used by default, which blocks the return of this function
                        (forever) until some text is available for return.

                        <br>Returns available <code>eventText</code>, or if a
                            timeout occurred while waiting <code>null</code>.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>timeOut </code>
        <td> Optional, timeout in milliseconds, i.e. time to wait for
             an <code>eventText</code> to appear, before returning.






        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;postEventText&quot; </code>
        <td colspan="2">Adds <code>eventText</code> to the <code>eventText</code> vector (list),
                        can be retrieved via <code>pollEventText</code>.
                       <br>Returns the received <code>eventText</code>

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>eventText </code>
        <td> Mandatory, text which should be put into the <code>eventText</code> vector.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>priority </code>
        <td> Optional, priority level of <code>eventText</code>, can be one of:
          *        <p><ul>
                   <li>&quot;<code>2</code>&quot;: high ('alarm level') priority.
                   <li>&quot;<code>1</code>&quot;: normal (<strong>default</strong>) priority, and
                   <li>&quot;<code>0</code>&quot;: low ('batch level') priority,
                   </ul>



        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;rawRegisterBean&quot; </code> or<br>
             <code>&quot;new&quot;</code> (a synonym)
        <td colspan="2">Uses the supplied <em>beanName</em> to store the supplied
                        <em>object</em> in the BSFRegistry.

        Creates a new object (instantiating the given Java class
                        with the given arguments) and registers it using the
                        given <em>beanName</em>.
                        <br>Returns <em>beanName</em>
                        (always use this returned beanName for looking up the
                        object in the registry).


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Name of the object to be created and registered.
             if no name is given (empty string or <code>null</code>)
             then a unique one will be created and returned;
             this is done in method {@link #makeBeanName(RexxAndJava rajo, Object o)}.


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanType</code>
        <td> Mandatory, type (Java class name) of the bean (Java object) to be
             created and registered.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>arg # 1</code>
        <td> The argument # 1 (if given).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>... arg # n</code>
        <td> The argument # n (if given).






        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;setFieldValue&quot; </code>
        <td colspan="2">Looks up a <em>public</em> field of the registered
                        object and sets it to the argument's value.
                        <br>

                        <em>Hint:</em> if the field could not be found, this subfunction
                        automatically attempts to employ a setter method (<code>fieldName</code>
                        prepended with the string &quot;set&quot;). If you do not want to use this
                        feature, then employ the subfunction <code>&quot;setFieldValueStrict&quot;</code> instead.

                        <br>Returns the new value of the field.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of the object to be looked up.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>fieldName </code>
        <td> Mandatory, name of the <em>public</em> field of the object.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>newValue </code>
        <td> The new value the field gets set to.




        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;setFieldValueStrict&quot; </code>
        <td colspan="2">Looks up a <em>public</em> field of the registered
                        object and sets it to the argument's value.
                        <br>Returns the new value of the field.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of the object to be looked up.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>fieldName </code>
        <td> Mandatory, <em>case sensitive</em> name of the <em>public</em> field of the object.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>typeIndicator </code>
        <td> <em>optional</em> type indicator for the immediately following argument
             (<code>newValue</code>) or <code>newValue</code>.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>newValue </code>
        <td> The new value the field gets set to. (If this argument is given, then the
             previous argument is interpreted as a <code>typeIndicator </code>.)






        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;setPropertyValue&quot; </code> <strong>(untested!)</strong>
        <td colspan="2">Looks up a <em>property</em> of the registered
                        <em>Java Bean</em> object and sets it to the argument's value.
                        <br>Returns the new value of the property.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of the Java Bean object to be looked up.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>propertyName </code>
        <td> Mandatory, name of the Java Bean <em>property</em>.


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>index </code>
        <td> Mandatory, <code>null</code>, if Java Bean property is not indexed,
             a valid integer number else.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>newValue </code>
        <td> The new value the property gets set to.






        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;setPropertyValueStrict&quot; </code> <strong>(untested!)</strong>
        <td colspan="2">Looks up a <em>property</em> of the registered
                        <em>Java Bean</em> object and sets it to the argument's value.
                        <br>Returns the new value of the property.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of the Java Bean object to be looked up.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>propertyName </code>
        <td> Mandatory, name of the Java Bean <em>property</em>.


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>index </code>
        <td> Mandatory, <code>null</code>, if Java Bean property is not indexed,
             a valid integer number else.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>typeIndicator </code>
        <td> Type indicator for the immediately following argument
             (<code>newValue</code>).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>newValue </code>
        <td> The new value the property gets set to.






        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;setRexxNullString&quot;</code>
        <td colspan="2">Sets the field {@link #null4Rexx} to the string which serves
                        as the representation for <code>null</code>.
                        <ul>
                        <li>The Java side will return this value to Rexx to indicate a Java
                            <code>null</code> (&quot;no value&quot;). This conversion is
                            done in method {@link #makeString4Rexx(Object o)}.

                        <li>The Rexx side can use this string for
                            an argument for which no value is supplied.
                            This option is available in addition to the standard Rexx option
                            of just leaving the missing argument empty. The conversion of
                            Rexx arguments to Java is done in
                            {@link #convFromRexx(String type, String value)}.
                        </ul>


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>newString </code>
        <td> Mandatory, the new string to be used to indicate a Java
            <code>null</code>.





        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;sleep&quot;</code>

        <td colspan="2">Sleeps <code>time2sleep</code> seconds before returning.


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code> time2sleep </code>
        <td align="left"> Mandatory, indicates seconds to sleep before returning. <code>time2sleep</code>.
                        The sleeping occurs with an attempted resolution of milliseconds,
                        being calculated like:
                        <code> (long) ((double)time2sleep*1000+0.5d)</code>, e.g. <br>
                   <ul>
                   <li><code>3</code> (three seconds, 3000 msec),
                   <li><code>600</code> (600 seconds, i.e. 10 minutes, 600000 msec),
                   <li><code>0.5</code> (5/10 second, i.e. half a second, 500 msec),
                   <li><code>0.01</code> (1/100 second, 10 msec),
                   <li><code>0.001</code> (1/1000 second,  1 msec),
                   <li><code>0.0005</code> (rounded up, ie. 1/1000 second, 1 msec),
                   <li><code>0.0004</code> (rounded down, ie. 0/1000 second, 0 msec).
                   </ul>

                   <p><em>Hint:</em> If available, use Rexx' <code>SysSleep()</code> function
                   instead (it is usually more exact).


        <!-- -------------------------------------------------------- -->

                   * value = BSF( 'strictArg', strType, strValue, bPrimitive )
     *
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;strictArg&quot;</code>

        <td colspan="2">Creates and returns an instance of RexxStrictArgument according
                        to the supplied (primitive) type indicator <code>type</code> and <code>value</code>.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>type </code>
        <td> Mandatory, one of
                    &quot;<strong>BO</strong>olean&quot; (i.e. '0' or '1'),
                    &quot;<strong>BY</strong>te&quot;,
                    &quot;<strong>C</strong>har&quot;,
                    &quot;<strong>D</strong>ouble&quot;,
                    &quot;<strong>F</strong>loat&quot;,
                    &quot;<strong>I</strong>nt&quot;,
                    &quot;<strong>L</strong>ong&quot;,
                    &quot;<strong>SH</strong>ort&quot;, and
                    &quot;<strong>ST</strong>ring&quot;.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>value </code>
        <td> Mandatory.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>bPrimitive</code>
        <td> Mandatory, if true, the primitive class object will be used, else the Wrapper class object.


        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;unbox&quot;</code>

        <td colspan="2">Fetches and returns a boxed value as a string, null else.

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName</code>
        <td> Mandatory.



        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;unregisterBean&quot; </code>
        <td colspan="2">Unregisters an object from the BSF manager's
                        object registry.
                        <br>Returns the former beanName of the just unregistered object.
     *                  <br>If the object could not be unregistered, because the reference
     *                      counter did not drop to 0, then <code>.NIL</code> is returned.


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>beanName </code>
        <td> Mandatory, name of bean (Java object) to be unregistered.



        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code>&quot;version&quot; </code>
        <td colspan="2">Returns the version of this program in the form of
              &quot;<code>version.YYYYMMMDDD package-name-of-engine info</code>&quot;, e.g.
              &quot;<code>272.20061210 org.rexxla.bsf.engines.rexx (org.apache.bsf)</code>&quot;
              for Apache's BSF, if no argument is given. Otherwise it returns the
              version of <code>BSFManager</code> or of the indicated class in
              the <code>org.rexxla.bsf.engines.rexx</code> package.


        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>classIndicator</code>
        <td> Optional. If no argument is given the version of this program is returned in
     *       the long format: &quot;<code>version.YYYYMMMDDD package-name-of-engine info</code>&quot;.
     *       <br>
     *       In the following list of arguments only the first uppercase characters need to
     *       be given:

     *       <table>
     *       <tr><td>&quot;<code>ALl<code>&quot;
     *           <td>Returns a blank delimited string with pairs of fully qualified class names
     *               and their version number in the form of <code>version.YYYYMMDD</code>.

     *       <tr><td>&quot;<code>ARrayWrapper<code>&quot;
     *           <td>Returns the version number of the <code>org.rexxla.bsf.engines.rexx.ArrayWrapper</code> class.

     *       <tr><td>&quot;<code>BSFManager<code>&quot;
     *           <td>Returns the version number of the <code>org.apache.bsf.BSFManager</code> class.

     *       <tr><td>&quot;<code>EnumerationWrapper<code>&quot;
     *           <td>Returns the version number of the <code>org.rexxla.bsf.engines.rexx.EnumerationWrapper</code> class.

     *       <tr><td>&quot;<code>Java4Rexx<code>&quot;
     *           <td>Returns the version number of the <code>org.rexxla.bsf.engines.rexx.Java4Rexx</code> class.

     *       <tr><td>&quot;<code>REXXAndJava<code>&quot;
     *           <td>Returns the version number of the <code>org.rexxla.bsf.engines.rexx.RexxAndJava</code> class.

     *       <tr><td>&quot;<code>REXXEngine<code>&quot;
     *           <td>Returns the version number of the <code>org.rexxla.bsf.engines.rexx.RexxEngine</code> class.

     *       <tr><td>&quot;<code>Supplier<code>&quot;
     *           <td>Returns the version number of the <code>org.rexxla.bsf.engines.rexx.Supplier</code> class.

     *       </table>




        <!-- -------------------------------------------------------- -->
        <tr class="TableHeadingColor"><!-- table row -->
        <td> <code> &quot;wrapEnumeration&quot; </code>
        <td colspan="2">Wraps the given object up in a {@link EnumerationWrapper}-object, allowing
                        Java 1.1 programs to use the methods of the Enumeration interface
                        (the problem: Java 1.1 raises an IllegalAccessException, if accessing
                        methods of inner classes; starting with 1.2 one can come by this bug
                        under program control).

        <tr class="TableRowColor"><!-- table row -->
        <td>
        <td align="right"> <code>enumerationObject </code>
        <td> Mandatory, name of a registered enumerationObject (received by Java).





        </table>
        <p>
      *
      *  @return A Rexx string or <code>null</code>.
      *
      */

    public String javaCallBSF (String args[])  throws BSFException
    {
        InvocationType choice=getInvocationType(args[0]);   // get invocation type


// System.err.println(this+".javaCallBSF(), args[0]=["+args[0]+"] ---> choice=["+choice+"] / args="+java.util.Arrays.deepToString(args)+" / BRRR ! ...");


        if (choice==null)
        {
            throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                     "'"+args[0]+"': unknown function name (no such function implemented)");
        }


/* // rgf, 2016-11-30: even if a Rexx engine got terminated it may be the case that UNINITs cause this method
   //                  to be invoked; as unregisterBean does not use the Rexx engine, but merely reduces the
   //                  refCounter for the Java object in the registry, we allow for "unregisterBean" operation
   //                  to proceed
*/
        // RexxAndJava got terminated, cannot use it anymore, do not serve it anymore
        if (bTerminated==true &&
              ( args==null ? true :              // args is null: allow ignoring this invocation
                    ( args.length==0 ? true :    // no args:  allow ignoring this invocation
                      ( ! (choice==UNREGISTER_BEAN) )     // if not "unregisterBean": allow ignoring this invocaton
        //              ( ! args[0].equalsIgnoreCase( STRING_UNREGISTER_BEAN))     // if not "unregisterBean": allow ignoring this invocaton
                    )
               )
            )
        {
            throw new RexxException("RexxAndJava "+this+" got terminated, cannot be used anymore.");
        }


        {
            final boolean bDebug= // true;  // if true, show debug infos
                                  false;
            if (bDebug)
            {
                System.err.println(this+".javaCallBSF(), args[0]=["+args[0]+"] ---> choice=["+choice+"] / args="+java.util.Arrays.deepToString(args)+" / BRRR ! ...");

                System.err.print(this+".javaCallBSF(...)"
                                   +"/rii_ID=["+this.rii_ID+"]"
                                   +", mgr=["+mgr+"]"
                                   +                 ", args[0]=["+args[0]+"]"
                                   +(args.length>1 ? ", args[1]=["+args[1]+"]" : "")
                                   +(args.length>2 ? ", args[2]=["+args[2]+"]" : "")
                                   +(args.length>3 ? ", args[3]=["+args[3]+"]" : "")
                                   +(args.length>4 ? ", args[4]=["+args[4]+"]" : "")
                                   +(args.length>5 ? ", args[5]=["+args[5]+"]" : "")
                                   +(args.length>6 ? ", args[6]=["+args[6]+"]" : "")
                                   );
                System.err.print("\n\t---> RexxAndJava.javaCallBSF(), args[0]=["+args[0]+"], nr args=["+args.length+"]: ");
                for (int i=1; i<args.length;i++)
                {
                    System.err.print(" "+i+"=["+args[i]+"]");
                }
                System.err.println();
            }
        }


       boolean bStrongTyping=false; // set to true, if Java types preceed the individual Rexx arguments

        // ==================================================================
        // ==================================================================

       switch (choice)
       {
          case ADD_EVENT_LISTENER :
                  {
                      if (!eventDeprecationWarningAlreadyGiven)
                      {
                          // since 2018-02-17
                          System.err.println("RexxAndJava: Deprecation warning: the (old asynchroneous) BSF4ooRexx \"event\" related subfunctions"
                                             + " \"[addEventListener,pollEventText,postEventText]\""
                                             + " may be removed sometimes in the future, please change the Rexx"
                                             + " program using this outdated subfunction as soon as possible!");
                          eventDeprecationWarningAlreadyGiven=true;    // do not show this warning anymore in this run
                      }

                  /* ********************************************************
                   * call BSF 'addEventListener', beanName, eventSetName, filter, script
                   *
                   * - beanName: the bean that fires the event
                   * - eventSetName: the set the event belongs to
                   * - filter: the actual event
                   * - script: the script to be run, if the event fires
                   *********************************************************/
                      if(args.length!=5)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args; usage: call BSF " +
                              "'"+args[0]+"', beanName, eventSetName, filter, script)");
                      }

                      Object bean = null;
                      bean=lookupBean(this, args[1]);

                      if(bean==null)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": object '"+args[1]+"' not registered");
                      }

                      args[3] = args[3].equals("") ? null : args[3];
                      try
                      {
// RgfMsgBox("BSF4ooRexx subfunction "+'"'+args[0]+'"'+" before invoking EngineUtils.addEventListener(...).",'1');
                          EngineUtils.addEventListener(bean, args[2], args[3],
                                                       rexxEngine, mgr, EVENT_TEXT,
                                                       0, 0, args[4]);
                          // return "1";   // return .true
// RgfMsgBox("BSF4ooRexx subfunction "+'"'+args[0]+'"'+" everything o.k., about to return .true.", '1');
                          return makeString4Rexx(this, "1");   // return .true
                      }
                      catch (BSFException e)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   // "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": could not add 'eventText', got BSF exception: [" + e.getMessage ()+"]");
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": could not add 'eventText', got exception: [" + e.toString ()+"]");
                      }
                  }
        // ==================================================================


    // ==================================================================
       case CREATE_ARRAY_OBJECT_OF:     // rgf, 2009-07-30
           /*******^**************************************************
            * value = BSF( 'createArrayOf', componentType, [val1] ...)
            *
            * - componentType: class object or a string with a fully qualified Java class name
            * - val1 ...: optional additional argument(s), each representing a value of componentType;
            *             if no values are given, then an array object will get created of size 0!
             *********************************************************/
           {
               if (args.length<2)
               {
                   throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                      "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": too few arguments, you must supply at least the \"componentType\" argument!");
               }

               Object o_componentType=null;
               try
               {
                   o_componentType=convFromRexx("O", args[1]);
               }
               catch (BSFException be)      // bean not registered exception ?
               {
                   // 2009-06-25, rgf: if argument is a string, then try to dynamically load the Java class and use that instead
                   try
                   {
                       // o_componentType=EngineUtils.loadClass(mgr, args[1]);
                       o_componentType=RexxReflectUtil.loadClass(this, choice.getMixedCase(), args[1]);

                       if (o_componentType==null)   // zut alors! (not found, hence throw appropriate exception
                       {
                           throw (new ClassNotFoundException (args[1]));
                       }
                   }
                   catch (Exception e)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                          "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" componentType ["+args[1]+"]"+
                          " is neither an instance of 'java.lang.Class', nor could a Java class by that name be dynamically loaded!"
                          , e  // rgf, 2011-06-04: supply Exception object
                          );
                   }
               }

               // ---------------->
               // throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
               //     "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" componentType ["+args[1]+"] is not an instance of 'Class'!");


               Class componentType=(Class) o_componentType;
               int   length=args.length-2;  // caclulate number of array elements
               Object arr=Array.newInstance( componentType, length); // create the array object of the desired length

               // determine number of element, create array object of given type, then assign the values to the array object
               for (int i=2; i<args.length; i++)    // iterate over arguments, convert and save them ...
               {
                   try
                   {
                       Object o_nv=convFromRexx(args[i]);

                       if (o_nv!=null && componentType.isPrimitive() )  // if not null, determine component type of array
                       {
                           TypeConvertor tc = glob_tcr.lookup(String.class, componentType);
                           o_nv=tc.convert(String.class, componentType, o_nv);
                       }

                       // assign value to array; if wrapper type and componentType is primitive, unwrapping/unboxing occurs automatically by Array.set(...)
                       Array.set(arr, i-2, o_nv);
                   }
                   catch (Exception e)
                   {
                       Throwable t=e.getCause();
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                              "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": processing argument with index # "+i+
                              " (value=\""+args[i]+"\") caused an exception"+
                              ( t==null ? "" : "(\""+t+"\")" )+
                              ", must be of componentType \""+componentType+"\""
                               , e  // rgf, 2011-06-04: supply Exception object
                          );
                   }
               }
// System.err.println(" /// "+this+" - CREATE_ARRAY_OBJECT_OF: arr=["+arr+"] --> ["+java.util.Arrays.toString((Object[])arr)+"]");
               return makeString4Rexx(this, arr);     // return the single dimensioned array object
           }


     // ==================================================================

       case CREATE_ARRAY_OBJECT:
           /*******^**************************************************
            * value = BSF( 'createArray', componentType, idx1 [, idx2 [, idx3 [, idx4 [, idx5]...]]] )
            *
            * - componentType: class object or a string with a fully qualified Java class name
            * - idx1 ... idx5: maximum entries per indicated dimension (idx1...idx5...)
            *   alternatively: idx1 can be a Java array of int
             *********************************************************/
           {
               Object o_componentType=null;

               try
               {
                   o_componentType=convFromRexx("O", args[1]);
               }
               catch (BSFException be)      // bean not registered exception ?
               {}

               if (! (o_componentType instanceof Class))    // not a class object in hand ?
               {
                   // 2009-06-25, rgf: if argument is a string, then try to dynamically load the Java class and use that instead
                   try
                   {
                       // o_componentType=EngineUtils.loadClass(mgr, args[1]);
                       o_componentType=RexxReflectUtil.loadClass(this, choice.getMixedCase(), args[1]);
                       if (o_componentType==null)   // zut alors! (not found, hence throw appropriate exception
                       {
                           throw (new ClassNotFoundException (args[1]));
                       }
                   }
                   catch (Exception e)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                          "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" componentType ["+args[1]+"]"+
                          " is neither an instance of 'java.lang.Class', nor could a Java class by that name be dynamically loaded!"
                          , e  // rgf, 2011-06-04: supply Exception object
                          );
                   }

                   // ---------------->
                   // throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                   //     "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" componentType ["+args[1]+"] is not an instance of 'Class'!");
               }

               Class componentType=(Class) o_componentType;

               int [] indices=null;     // define a variable to hold an int-array for the indices
               int firstIdx=2;

               if (args[firstIdx].charAt(0) == '[')         // an array in hand !
               {
                   Object o_idx=convFromRexx("O", args[firstIdx]);

                   // ArrayWrapper aw=ArrayWrapper.getArrayWrapper(o_idx);  // get
                   // rgf, 2009-09-10
                   ArrayWrapper aw=null;

                   try {
                       aw=new ArrayWrapper(o_idx);  // get
                   }
                   catch (ClassNotFoundException cnfe)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                            "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" index array object, class object of 'componentType' not found!", cnfe);
                   }


                   if (aw.componentType != int.class)       // check array of indices for correct class
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                            "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" index array object ["+args[firstIdx]+"] not of type 'int'!");
                   }
                   indices=(int []) o_idx;                  // o.k., assign to int-array
               }
               else // individual indices, create an array of int's for it
               {
                   indices=new int [ args.length-firstIdx ];  // calculate & reserve needed array-size
                   int i=0, j=firstIdx;
                   for ( ; j<args.length; i++, j++)
                   {
                       indices[i]=Integer.parseInt(args[j]);
                   }
               }

               Object arr=Array.newInstance( componentType, indices); // create the array object
               return makeString4Rexx(this, arr);     // return the array object
           }


       // ==================================================================

       case ARRAY_AT:
          /*********************************************************
           * value = BSF( 'arrayAt', arrayObject, idx1 [, idx2 [, idx3 [, idx4 [, idx5]...]]] )
           *
           * - arrayObject:   array to be worked upon
           * - idx1 ... idx5 ...: index values for arrays
           *   alternatively: idx1 can be a Java array of int
            *********************************************************/
       case ARRAY_PUT:
           /*********************************************************
            * value = BSF( 'arrayPut', arrayObject, "newValue", idx1 [, idx2 [, idx3 [, idx4 [, idx5]...]]] )
            *
            * - arrayObject:   array to be worked upon
            * - newValue:      new value to set array element to
            * - idx1 ... idx5 ...: index values for arrays
            *   alternatively: idx1 can be a Java array of int
            *********************************************************/

       case ARRAY_PUT_STRICT :
           /*********************************************************
            * value = BSF( 'arrayPut', arrayObject, "argType", "newValue", idx1 [, idx2 [, idx3 [, idx4 [, idx5]...]]] )
            *
            * - arrayObject:   array to be worked upon
            * - argType:       type of "newValue"
            * - newValue:      new value to set array element to
            * - idx1 ... idx5 ...: index values for arrays
            *   alternatively: idx1 can be a Java array of int
            *********************************************************/

       case WRAP_ARRAY_OBJECT:
           /*********************************************************
            * value = BSF( 'arrayWrap', arrayObject)
            *
            * - arrayObject:   array to be worked upon
            *********************************************************/

           {
               final boolean bDebug= // true;    // if true, show debug infos
                                     false;

               if (args[1].charAt(0) != '[')    // not an array object!
               {
                   throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                            "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" array object ["+args[1]+"] is not an array!");
               }

if (bDebug)
{
    System.err.println(this+": *ARRAY*:  args[0]=["+args[0]+"]");
    for (int i=0; i<args.length; i++)
    {
        System.err.println("\targs["+i+"]=["+args[i]+"]");
    }

}


               Object arrayObj = null;
               arrayObj=lookupBean(this, args[1]);

               if (arrayObj == null)
               {
                   throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                            "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" array object ["+args[1]+"] not registered!");
               }


               if (choice==WRAP_ARRAY_OBJECT)     // create and return the ArrayWrapper
               {
                   // return makeString4Rexx( new ArrayWrapper(arrayObj) ); // get the element and return it to Rexx

                   // rgf, 2009-09-10
                   ArrayWrapper aw=null;

                   try {
                       aw=new ArrayWrapper(arrayObj);  // get
                   }
                   catch (ClassNotFoundException cnfe)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                            "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" class object of 'componentType' not found!", cnfe);
                   }
                   return makeString4Rexx(this, aw);  // return ArrayWrapper instance
               }


               if (args.length< (choice==ARRAY_AT ? 3 : 5) )   // not enough arguments?
               {
                   String errMsg = "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args; usage: value = BSF( " +
                                    "'"+args[0]+"', arrayObject,"+
                                                   (choice==ARRAY_AT ? "" : " argType, newValue,") +
                                    " indexArray of int |or comma-separated indices| idx1 [, idx2]...";
               }

               Object o=null, o_nv=null;

               // ArrayWrapper aw=ArrayWrapper.getArrayWrapper(arrayObj); // get wrapper, so we know which component type it has
               // ArrayWrapper aw=new ArrayWrapper(arrayObj); // get wrapper, so we know which component type it has
               // rgf, 2009-09-10
               ArrayWrapper aw=null;

               try {
                   aw=new ArrayWrapper(arrayObj);  // get
               }
               catch (ClassNotFoundException cnfe)
               {
                   throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                        "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" class object of 'componentType' not found!", cnfe);
               }

               int firstIdx=2;          // first argument with index-information, default to arrayAt()

               if (choice==ARRAY_PUT_STRICT)
               {
                   // o_nv=convFromRexx( args[2], args[3] );     // get the Java object
                   // not needed to invoke convFromRexx(), we use RexxStrictArgument directly
                   // o_nv=((RexxStrictArgument) convFromRexx( args[2], args[3]) ).value;     // get the Java object

                   // arg[2] is either a Rexx type indicator or the pre-registered
                   //        primitive/wrapper (starts with uppercase letter) type:
                   //        - "boolean.class byte.class char.class double.class float.class int.class long.class short.class"
                   //        - "Boolean.class Byte.class Character.class Double.class Float.class Integer.class Long.class Short.class "
                   // not really needed to distinguish as we are only interested in the value (always in a wrapper object)
                   // String  firstChar=args[2].substring(0,1);    // extract first character
                   // String  firstCharLC=firstChar.toLowerCase();
                   // boolean bPrimitiveClass=(firstChar.charAt(0)==firstCharLC.charAt(0);
                   //
                   // short-circuiting: if first letter is lowercase, then
                   // o_nv=new RexxStrictArgument(this, args[2], args[3], bPrimitiveClass).value;

                   o_nv=new RexxStrictArgument(this, args[2], args[3], true).value;

if (bDebug)
System.err.println("ARRAY_PUT_STRICT:  args[2]=["+args[2]+"], "+"args[3]=["+args[3]+"]: o_nv=["+o_nv+"]");
                   firstIdx=4;          // first argument with index-information for arrayPut()
               }
               else if (choice==ARRAY_PUT)      // convert Rexx argument to be stored in array to the appropriate type
               {
                   o_nv=convFromRexx(args[2]);  // get Java null or Java object from BSF registry, String else

                   Class cl=arrayObj.getClass(),
                         ct=aw.componentType;
                   // rgf, 2018-01-01: only use a type convertor if convFromRexx returned a string
                   if (o_nv!=null && o_nv instanceof String && ct.isPrimitive() )      // if not null, determine component type of array
                   {
                       // rgf, 20180104: special case Boolean values: behave like SET_FIELD, where only
                       if ( (ct==boolean.class || ct==Boolean.class) && ((String) o_nv).equals("1") )
                       {
                           o_nv=Boolean.TRUE;
                       }
                       else     // use corresponding type convertor
                       {
                           TypeConvertor tc = glob_tcr.lookup(String.class, ct);
                           o_nv=tc.convert(String.class, ct, o_nv);
                       }

                   }

                   firstIdx=3;          // first argument with index-information for arrayPut()
               }

                    // check index-information: was an array passed in or individual index-values ?
               int [] indices=null;     // define a variable to hold an int-array for the indices

               if (args[firstIdx].charAt(0) == '[')         // an array in hand !
               {
                   Object o_idx=convFromRexx("O", args[firstIdx]);

                    // get and test component type
                   // if (ArrayWrapper.getArrayWrapper(o_idx).componentType != int.class)       // check array of indices for correct class

                   // rgf, 2009-09-10
                   ArrayWrapper aw2=null;

                   try {
                       aw2=new ArrayWrapper(o_idx);  // get
                   }
                   catch (ClassNotFoundException cnfe)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                            "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" class object of 'componentType' not found!", cnfe);
                   }

                   // if (new ArrayWrapper(o_idx).componentType != int.class)       // check array of indices for correct class
                   if (aw2.componentType != int.class)       // check array of indices for correct class
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                            "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" index array object ["+args[firstIdx]+"] not of type 'int'!");
                   }
                   indices=(int []) o_idx;                  // o.k., assign to int-array
               }
               else // individual indices, create an array of int's for it
               {
                   indices=new int [ args.length-firstIdx ];  // calculate & reserve needed array-size
                   int i=0, j=firstIdx;
                   for ( ; j<args.length; i++, j++)
                   {
                       indices[i]=Integer.parseInt(args[j]);
                   }
               }

               // aw=ArrayWrapper.getArrayWrapper(arrayObj);  // get
               // aw=new ArrayWrapper(arrayObj);  // get

               // rgf, 2009-09-10
               try {
                   aw=new ArrayWrapper(arrayObj);  // get
               }
               catch (ClassNotFoundException cnfe)
               {
                   throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                        "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" class object of 'componentType' not found!", cnfe);
               }


               if (choice==ARRAY_AT)
               {
if (bDebug)  System.err.println("ARRAY_AT(): aw.get(indices)=["+aw.get(indices)+"]...");
                   return makeString4Rexx(this, aw.get(indices)); // get the element and return it to Rexx
               }
               else
               {
                   aw.put(o_nv, indices);           // put the element into the array
               }
           }
           break;



          case ARRAY_LENGTH       :
                  {
                  /* ********************************************************
                   * value = BSF( 'arrayLength', arrayObject )
                   * returns the value of the array field 'length'
                   *
                   * - arrayObject:   array to be worked upon
                   *
                   *********************************************************/
                      if (args.length!=2)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args; usage: value = BSF( " +
                                  "'"+args[0]+"', arrayObject )");
                      }
                      Object arrayObj = null;

                      arrayObj=lookupBean(this, args[1]);

                      int    num      = Array.getLength( arrayObj ) ;
                      // return makeString4Rexx ( this, new Integer(num) );
                      return makeString4Rexx ( this, Integer.valueOf(num) );
                  }
        // ==================================================================

           case CREATE_STRICT_ARGUMENT :        // rgf, 2018-11-01
               {
                  /* ********************************************************
                   * value = BSF( 'strictArg', strType, strValue, bPrimitive )
                   * returns an instance of RexxStrictArgument
                   *
                   *********************************************************/
                      if (args.length<3 || args.length>4)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args; usage: value = BSF( " +
                                  "'"+args[0]+"', type, value [, bPrimitive] )");
                      }
                      // get objects from registry, if registered; determine whether .nil/null (if using without BSF.CLS)
                      Object oType =convFromRexx(args[1]);
                      Object oValue=convFromRexx(args[2]);

                      if (oType==null && oValue==null)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" argument \"type\" must not be [null], if argument value is [null]");
                      }

                      if (oType==null)   // argument with value <null> to be strictly used for supplied type
                      {
                          return makeString4Rexx ( this, new RexxStrictArgument(oValue) );
                      }
/*
                      else if (oValue==null) // a null that should be strictly used with the supplied type
                      {
                          if (! (oType instanceof Class) )
                          {
                              throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                       "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" argument \"type\" must be a java.lang.Class object, supplied bean name: ["+args[1]+"], which resolves to: ["+oType+"]");
                          }

                          return makeString4Rexx ( this, new RexxStrictArgument((Class)oType, oValue) );
                      }
*/
                      else if (! (oType instanceof String) )
                      {
                          if (! (oType instanceof Class) )
                          {
                              throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                       "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" argument \"type\" must be a java.lang.Class object, supplied bean name: ["+args[1]+"], which resolves to: ["+oType+"]");
                          }
                          return makeString4Rexx ( this, new RexxStrictArgument((Class)oType, oValue) );
                      }

                      if (Character.toUpperCase(args[1].charAt(0))=='O')   // "Object"? Use appropriate constructor.
                      {
                          return makeString4Rexx ( this, new RexxStrictArgument(oValue) );
                      }

                      // rexx indicator type version, all arguments are strings
                      boolean bPrimitive=true;      // default to true (set classObject to primitive class object)
                      if (args.length==4 && args[3]!=null)
                      {
                          if (args[3].length()==1)
                          {
                              bPrimitive=(args[3].equals("1"));
                          }
                          else   // will yield .true only, if supplied string equlas 'true'
                          {
                              bPrimitive=Boolean.valueOf(args[3]);
                          }
                      }

                        // get and return RexxStrictArgument; make sure usable if not employing BSF.CLS
                      return makeString4Rexx (this, new RexxStrictArgument(this, args[1], args[2], bPrimitive) );

               }
               // ==================================================================


          case EXIT               :
                  {
                  /* ********************************************************
                   * call BSF 'exit' [, return_value [, time2sleep] ]
                   * terminates the JVM; returns the string "SHUTDOWN, REXX !"
                   * - retVal : optional return value
                   * - msecs  : optional msecs to sleep before terminating the JVM
                   *********************************************************/
                      int  rc=0;                  // return code
                      long msecs2sleep=100l;      // msecs to sleep (default: 1/10 sec)

                      if (args.length > 1)
                      {
                         rc=Integer.parseInt(args[1]);    // get return code, if supplied
                                                          // get milliseconds to sleep
                         if (args.length > 2) msecs2sleep = Long.parseLong(args[2]);
                      }

                      // rgf, 2011-02-09: controls whether System.exit is carried out or not
                      if (carryOutSystemExit==true)
                      {
                              // rgf, 2012-02-06: make sure  no callbacks from Java to Rexx occur anymore
                          ((RexxEngine)rexxEngine).bTerminated=true;

                              // create and start the delayed exit thread
                          new Thread( new ExitDelayed(rc, msecs2sleep) ) .start();

                      }
                      // return "SHUTDOWN, REXX !";  // indicate to Rexx what to do ... ;)
                      return makeString4Rexx(this,"SHUTDOWN, REXX !");
                  }
        // ==================================================================

       case GET_BSF_MANAGER    :
               {
               /* ********************************************************
                * call BSF 'getBSFManager'
                * returns the current BSFMananger instance
                *********************************************************/

                   if (args.length > 1)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" does not expect any argument!");
                   }
                   return makeString4Rexx(this,this.mgr);    // return the BSFManager instance
               }

      // ==================================================================

       case GET_REXX_AND_JAVA  :
               {
               /* ********************************************************
                * call BSF 'getRexxAndJava'
                * returns the this RexxAndJava instance
                *********************************************************/

                   if (args.length > 1)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" does not expect any argument!");
                   }
                   return makeString4Rexx(this,this);    // return this instance
               }

      // ==================================================================

       case GET_REXX_ENGINE  :
               {
               /* ********************************************************
                * call BSF 'getRexxEngine'
                * returns the current BSFMananger instance
                *********************************************************/

                   if (args.length > 1)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" does not expect any argument!");
                   }
                   return makeString4Rexx(this, this.getRexxEngine());    // return this instance
               }


      // ==================================================================

       case GET_FIELD_VALUE                   :
       case SET_FIELD_VALUE                   :
       case GET_FIELD_VALUE_STRICT            :
       case SET_FIELD_VALUE_STRICT            :
       case GET_FIELD_VALUE_JSO               :
       case GET_FIELD_VALUE_STRICT_JSO        :

            // actually not really needed anymore, but leaving to support old BSF4ooRexx programs
       case GET_STATIC_FIELD_VALUE            :
       case GET_STATIC_FIELD_VALUE_JSO        :
       case GET_STATIC_FIELD_VALUE_STRICT     :
       case GET_STATIC_FIELD_VALUE_STRICT_JSO :
               {

                   /* ********************************************************
                    * object = BSF( 'getFieldValue',          beanName, fieldName )
                    * object = BSF( 'getFieldValueStrict',    beanName, fieldName ) // case sensitive fieldName
                    * object = BSF( 'setFieldValueStrict',    beanName, fieldName, argType, newValue )
                    * object = BSF( 'setFieldValue',          beanName, fieldName, newValue )
                    *
                    * - beanName: the bean to lookup
                    * - fieldName: the bean to lookup
                    * - returns:  the String rendering of the bean or null, if not found
                    *********************************************************/


                   final boolean bDebug= // true;   // if true, show debug infos
                                         false;
if (bDebug)
{
    System.err.println("//// "+choice+" \\\\: args.length=["+args.length+"], args=\""+Arrays.deepToString(args)+"\"");
}

                  String tmp = null;        // new 2001-04-25, edited: 2003-05-10

                  switch (choice)
                  {
                      case GET_FIELD_VALUE                   :
                      case GET_FIELD_VALUE_STRICT            :
                      case GET_STATIC_FIELD_VALUE            :
                      case GET_STATIC_FIELD_VALUE_STRICT     :
                      case GET_FIELD_VALUE_JSO               :
                      case GET_FIELD_VALUE_STRICT_JSO        :
                      case GET_STATIC_FIELD_VALUE_JSO        :
                      case GET_STATIC_FIELD_VALUE_STRICT_JSO :
                                  if (args.length!=3)                 tmp="fieldName";
                                  break;

                      case SET_FIELD_VALUE                   :
                                  if (args.length != 4)               tmp="fieldName, newValue";
                                  break;

                      case SET_FIELD_VALUE_STRICT             :
                                  if (args.length<4 || args.length>5) tmp="fieldName, [newValueType,] newValue";
                                  break;
                  }

                  if (tmp != null)        // wrong number of arguments
                  {
                      throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                               "BSF4ooRexx subfunction \""+args[0]+"\": wrong number of arguments ("+args.length+")"
                                  + (args.length>0 ? ", supplied arguments: \""+Arrays.deepToString(args)+"\"" : "")
                                  + "; usage: value=BSF("+args[0]+", beanName, " +tmp+" )."
                                  );
                  }


                  // rgf, 2018-02-17, new reflection code
                  RexxReflectUtil rru=new RexxReflectUtil(this, choice, args);

                  if (bDebug) System.err.println("RexxAndJava: about to reflect for subfunction \""+choice+"\": "+rru+": "+rru.debugString());
// System.err.println("\n\n/// RAJ, l# 3400, choice=["+choice+"] - before rxReflector.reflect(rru) // args.length=["+args.length+"], args=\""+Arrays.deepToString(args)+"\"");
                  rxReflector.reflect(rru);     // BSFException may get raised, do not intercept
// System.err.println("\n\n/// RAJ, l# 3402, choice=["+choice+"] - AFTER  rxReflector.reflect(rru) // args.length=["+args.length+"], args=\""+Arrays.deepToString(args)+"\"");

                  if (rru.success)
                  {
                      if (rru.bReturnJSO)     // we need to return a JSO (Java String object), not the String value
                      {
                          if (rru.result instanceof String)
                          {
                          // register result as a bean and return it
                           String beanName = makeBeanName(this, rru.result);
                           return registerBean(this, beanName, rru.result);
                          }

                          // if a NetRexx object, get its String value and return it as a JSO
                          if (nlR_class!=null && rru.result.getClass()==nlR_class)
                          {
                              try {
                                  String nrxStr=(String) nlR_toString.invoke(rru.result, (Object[]) null);
                                  // register result as a bean and return it
                                  String beanName = makeBeanName(this, nrxStr);
                                  return registerBean(this, beanName,  nrxStr);
                              }
                              catch (Exception e) {};
                          }
                      }

                      return makeString4Rexx(this, rru.result);   // return whatever object we got
                  }

                  // no matching Field object found
                  if (rru.throwable != null)
                  {
                      throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                               "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": cannot find appropriate field ["+args[2]+"] in object ["+args[1]+"]",
                                              rru.throwable);       // supply the Throwable from trying to invoke while searching for a Field
                  }
                  throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                           "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": cannot find appropriate field ["+args[2]+"] in object ["+args[1]+"]");
               }    // end-of- *_FIELD_*




      // ==================================================================

          case GET_PROPERTY_VALUE        :
          case GET_PROPERTY_VALUE_JSO    : // rgf, 2014-10-05

          case SET_PROPERTY_VALUE        :
          case SET_PROPERTY_VALUE_STRICT :
                  {

                      final boolean bDebug= // true;   // if true, show debug infos
                                            false;

if (bDebug)
{
    System.err.println("//// PROPERTY \\\\: args.length=["+args.length+"], args=\""+Arrays.deepToString(args)+"\"");
}
                     /* ********************************************************
                      * object = BSF( 'getPropertyValue',       beanName, fieldName, index )
                      * object = BSF( 'setPropertyValueStrict', beanName, fieldName, index, argType, newValue )
                      * object = BSF( 'setPropertyValue',       beanName, fieldName, index, newValue )
                      *
                      * - beanName: the bean to lookup
                      * - fieldName: the bean to lookup
                      * - returns:  the String rendering of the bean or null, if not found
                      *********************************************************/

                     String tmp = null;        // new 2001-04-25, edited: 2003-05-10
                     String fieldName=args[2];    // store received fieldName

                          if (choice==GET_PROPERTY_VALUE        && (args.length!=3 && args.length!=4)) tmp= "propertyName[, index]";
                     else if (choice==SET_PROPERTY_VALUE        &&  args.length!=5) tmp= "propertyName, index, newValue";
                     else if (choice==SET_PROPERTY_VALUE_STRICT &&  args.length!=6) tmp= "propertyName, index, newValueType, newValue";

                     if (tmp != null)        // wrong number of arguments
                     {
                         throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                  "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": wrong number of arguments ("+args.length+");"
                                     +" usage: value=BSF("+args[0]+", beanName, " +tmp+" ).");
                     }

// rgf, 201801: removed _FIELD_ logic to separate block; not supporting PROPERTY in the future, hence give a deprecation warning
                     if (!propertyDeprecationWarningAlreadyGiven)
                     {
                         // since 2018-02-17
                         System.err.println("RexxAndJava: Deprecation warning: the BSF4ooRexx \"property\" related subfunctions"
                                            + " \"[getPropertyValue,getPropertyValueJSO,setPropertyValue,setPropertyValueStrict]\""
                                            + " may be removed sometimes in the future, please change the Rexx"
                                            + " program using this outdated subfunction as soon as possible!");
                         propertyDeprecationWarningAlreadyGiven=true;    // do not show this warning anymore in this run
                     }

                     Object o = null;
                     o=lookupBean(this, args[1]);

                     if (o==null)
                     {
                         throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                  "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": bean '"+args[1]+"' not registered.");
                     }

                     try
                     {
                         Bean    bean  = null;
                         Integer index = null;

                         if ( args.length>=4 && args[3]!=null && (!args[3].equals("")) )
                                  index=Integer.parseInt(args[3]);            // get Integer from String

                         bean=ReflectionUtils.getProperty(o, args[2], index);

                         if (
                             choice==GET_PROPERTY_VALUE         ||
                             choice==GET_PROPERTY_VALUE_JSO
                             )
                         {

// rgf, 2014-10.04: temporatily force java.lang.String
// bean.value=bean.value.toString();

                             if ( (
                                  choice==GET_PROPERTY_VALUE_JSO
                                 ) &&
                                 bean.value != null &&
                                 ( bean.value instanceof String || (nlR_class!=null && bean.value.getClass()==nlR_class) )
                                )
                             {
                                 // register result as a bean and return it
                                  String beanName = makeBeanName(this, bean.value);
                                  return registerBean(this, beanName, bean.value);
                             }

                             // not a String nor NetRexx object to be returned
                             return makeString4Rexx(this, bean.value);             // return whatever we got
                         }


                         // this section sets fields/properties
                         try         // now set the field/property to the new value
                         {
                             if      (args.length==5 && args[4]==null) bean.value=null; // SET_PROPERTY_VALUE to null
                             else if (args.length==6 && args[5]==null) bean.value=null; // SET_PROPERTY_VALUE_STRICT to null

                             else if (choice==SET_PROPERTY_VALUE)
                             {
                                 // relaxed version, need to determine type
                                 Object tmpValue=convFromRexx(args[4]);
                                 if (tmpValue != null && (bean.type).isPrimitive())
                                 {
                                     // convert Rexx argument to Java
                                     TypeConvertor tc=glob_tcr.lookup(String.class, bean.type);
                                     tmpValue=tc.convert(String.class, bean.type, tmpValue);
                                 }
                                 bean.value=tmpValue;
                             }
                             // strict (type explicitly stated):
                             else bean.value=convFromRexx(args[4], args[5]);

                             ReflectionUtils.setProperty(o, args[2], index, bean.value, bean.type, glob_tcr);

                             // return received value-string (don't know why, but keeping it for back-compatibility, --rgf, 2003-05-10
                             // return args[args.length-1];
                             return makeString4Rexx(this, args[args.length-1]);
                         }
                         catch (Exception e)
                         {
                            throw new BSFException (BSFException.REASON_EXECUTION_ERROR,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": exception while setting property"
                                      +" ["+ args[2]+"] in object ["+args[1]+"] to ["+ (args.length>4 ? args[4] : args[3]) +"]"
                                      +"\n, exception thrown: ["+e.toString()+"]"     // rgf, 2008-07-09
                                      , e  // rgf, 2011-06-04: supply Exception object
                                      );
                         }

                     }
                     catch (Exception e)
                     {
                        throw new BSFException (BSFException.REASON_EXECUTION_ERROR,
                               "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": exception while accessing property"
                                  +" ["+args[2]+"] in object ["+args[1]+"]"
                                  +"\n, exception thrown: ["+e.toString()+"]"     // rgf, 2008-07-09
                                  , e  // rgf, 2011-06-04: supply Exception object
                                  );
                     }
                  }
        // ==================================================================

           case INVOKE             :
           case INVOKE_STRICT      :
           case INVOKE_JSO         :
           case INVOKE_STRICT_JSO  :
               {
                   final boolean bDebug= false;
                                         // true;


                   if (choice==INVOKE_JSO || choice==INVOKE)        // check arguments
                   {
                      /* ********************************************************
                       * value = BSF( 'invoke', [beanName], function [, arg]... )
                       *
                       * - beanName: the bean whose method is to be invoked
                       * - function: the function's name
                       * - arg: the argument's value
                       *********************************************************/

                       if (args.length<3)
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                    "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args; usage: value = BSF( " +
                                   "'"+args[0]+"', beanName, function [, arg]... )");
                       }

                   }
                   else
                   {
                      /* ********************************************************
                       * value = BSF( 'invokeStrict', [beanName], function [, argType, arg]... )
                       *
                       * - beanName: the bean whose method is to be invoked
                       * - function: the function's name
                       * - argType: the type of an argument
                       * - arg: the argument's value
                       *********************************************************/

                       if((args.length<3) || ((args.length-3)%2!=0))
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                    "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args; usage: value = BSF( " +
                                   "'"+args[0]+"', beanName, function [, argType, arg]... )");
                       }
                   }



    if (bDebug)
    {
        System.err.print("\n==> "+choice+" <=== ");
        System.err.println("invoke: beanName=["+args[1]+"], function: ["+args[2]+"] args.length="+args.length+", args=\""+Arrays.deepToString(args)+"\"");
    }


                    // rgf, 2018-02-17, new reflection code
                    RexxReflectUtil rru=new RexxReflectUtil(this, choice, args);

                    if (bDebug) System.err.println(this+": ---rgf-debug: "+rru+": "+rru.debugString());

// System.err.println("\n\n/// RAJ, l# 3651, choice=["+choice+"] - before rxReflector.reflect(rru) // args.length=["+args.length+"], args=\""+Arrays.deepToString(args)+"\"");
// try {

                     rxReflector.reflect(rru);
// } catch (Throwable t) {System.err.println("\n\n/// RAJ: # 3658 CAUGHT, CAUGHT: t=["+t+"]\n"); t.printStackTrace();System.err.println("t.getCause()=["+t.getCause()+"]\n");}

// System.err.println("\n\n/// RAJ: # 3657   (AFTER rxReflector.reflect(rru):\n/// \trru.memberName=["+rru.memberName+"], rru.success=["+rru.success+"], rru.throwable=["+rru.throwable+"]\n,rru.debugString()=["+rru.debugString()+"]\n"+"\n");

                    if (rru.success)
                    {
                        if (rru.bReturnJSO)     // we need to return a JSO (Java String object), not the String value
                        {
                            if (rru.result instanceof String)
                            {
                            // register result as a bean and return it
                             String beanName = makeBeanName(this, rru.result);
                             return registerBean(this, beanName, rru.result);
                            }

                            // if a NetRexx object, get its String value and return it as a JSO
                            if (nlR_class!=null && rru.result.getClass()==nlR_class)
                            {
                                try {
                                    String nrxStr=(String) nlR_toString.invoke(rru.result, (Object[]) null);
                                    // register result as a bean and return it
                                    String beanName = makeBeanName(this, nrxStr);
                                    return registerBean(this, beanName,  nrxStr);
                                }
                                catch (Exception e) {};
                            }
                        }
// rgf, 20181030, temporarily: System.err.println("\n===> INVOKE... SUCCESSFUL, rru.debugString=["+rru.debugString()+"]\n<===\n" );

                        return makeString4Rexx(this, rru.result);   // return whatever we have
                    }

                    // no matching Method object found or execution error
                    if (rru.throwable != null)
                    {
// System.err.println("//// RAJ --- 1");
// rgf, 20181030, temporarily: System.err.println(this+": rru.throwable="+rru.throwable);
                        throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                 "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": "+
                                 "\n\tbean:   ["+truncObject(rru.bean,65)+"] type: ["+rru.beanClz+"]"+
                                 "\n\tmethod: ["+args[2]+"] not found or execution error!",
                                rru.throwable);       // supply the Throwable from trying to invoke while searching for a Method
                    }
// System.err.println("//// RAJ --- 2 \\\\\\");
                    throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                             "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": "+
                             "\n\tbean:   ["+truncObject(rru.bean,65)+"] type: ["+rru.beanClz+"]"+
                             "\n\tmethod: ["+args[2]+"] not found!"
                             );
              }


        // ==================================================================


          case IS_INSTANCE :
                  {
                  /* ********************************************************
                   * call BSF 'isA', javaObject , javaClass
                   *
                   * javaObject:    test if instance of javaClass
                   * javaClass:     a class object or a string denoting a class/interface
                   *********************************************************/
                      if(args.length!=3)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: value = BSF( " +
                              "'"+args[0]+"', javaObject, javaClass)");
                      }

                      Object javaObject=null;
                      javaObject=lookupBean(this, args[1]);

                      if (javaObject==null)     // not in BSFRegistry, use string object directly
                      {
                          javaObject=args[1];   // rgf, 20181111
                      }

                      Object javaClass = null;
                      javaClass=lookupBean(this, args[2]);

                      if(javaClass==null)       // not in BSFRegistry, try to laod class
                      {
                          try
                          {
                              // javaClass=EngineUtils.loadClass(mgr, args[2]);    // try to load class
                              javaClass=RexxReflectUtil.loadClass(this, choice.getMixedCase(), args[2]);
                              if (javaClass==null)         // not found
                              {
                                  throw (new ClassNotFoundException (args[2]));
                              }
                          }
                          catch (Exception e)
                          {
                              throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                 "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": javaClass ["+args[2]+"]"+
                                 " is neither an instance of 'java.lang.Class', nor could a Java class by that name be dynamically loaded!"
                                 , e  // rgf, 2011-06-04: supply Exception object
                                 );
                          }
                      }
                        // carry out the test and return .true or .false accordingly
                      return makeString4Rexx(this, ((Class)javaClass).isInstance(javaObject) ? "1" : "0" );
                  }



        // ==================================================================

          case GET_VERSION        :
                  {
                  /* ********************************************************
                   * object = BSF( 'version' )
                   *
                   * - returns:  the String with the version information:
                   *             package_name package_version version_number.dateOfVersion
                   *********************************************************/

                      if (args.length>2)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args;\nusage: value = BSF( " +
                                  "'"+args[0]+"' [, ALl|ARrayWrapper|BsfManager|EnumerationWrapper|Java4Rexx|REXXAndJava|REXXEngine|Supplier] )");
                      }

                      if (args.length==1)   // no argument given, return
                      {
                          return makeString4Rexx(this, RAJ_VERSION );
                      }

                        // get argument in uppercase
                      String uCase= (args[1]==null ? "" : args[1].toUpperCase());
                      if (uCase.startsWith("AL"))           // ALl
                      {
                          String conc=" ";
                          return makeString4Rexx(this,
                              pkgName         +".ArrayWrapper "      +ArrayWrapper.version       +conc+
                              "org.apache.bsf"+".BSFManager "        +mgr.getVersion()           +conc+
                              pkgName         +".EnumerationWrapper "+EnumerationWrapper.version +conc+
                              pkgName         +".Java4Rexx "         +Java4Rexx.version          +conc+
                              pkgName         +".RexxAndJava "       +RexxAndJava.version        +conc+
                              pkgName         +".RexxEngine "        +RexxEngine.version         +conc+
                              pkgName         +".Supplier "          +Supplier.version
                          );
                      }
                      else if (uCase.startsWith("AR"))
                      {
                          return makeString4Rexx(this, pkgName+".ArrayWrapper "+ArrayWrapper.version);
                      }
                      else if (uCase.startsWith("B"))
                      {
                          return makeString4Rexx(this, "org.apache.bsf"+".BSFManager "+mgr.getVersion());
                      }
                      else if (uCase.startsWith("E"))
                      {
                          return makeString4Rexx(this, pkgName+".EnumerationWrapper "+EnumerationWrapper.version);
                      }
                      else if (uCase.startsWith("J"))
                      {
                          return makeString4Rexx(this, pkgName+".Java4Rexx "+Java4Rexx.version);
                      }
                      else if (uCase.startsWith("REXXA"))
                      {
                          return makeString4Rexx(this, pkgName+".RexxAndJava "+RexxAndJava.version);
                      }
                      else if (uCase.startsWith("REXXE"))
                      {
                          return makeString4Rexx(this, pkgName+".RexxEngine "+RexxEngine.version);
                      }
                      else if (uCase.startsWith("S"))
                      {
                          return makeString4Rexx(this, pkgName+".Supplier "  +Supplier.version);
                      }

                      throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                               "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid argument ["+args[1]+"];\nusage: value = BSF( " +
                               "'"+args[0]+"' [, ALl|ARrayWrapper|BsfManager|EnumerationWrapper|Java4Rexx|REXXAndJava|REXXEngine|Supplier] )");
                      // return makeString4Rexx( RAJ_VERSION );
                  }
        // ==================================================================




       case LOOKUP_BEAN        :
               {
               /* ********************************************************
                * object = BSF( 'lookup', beanName )
                *
                * - beanName: the bean to lookup
                * - returns:  the String rendering of the bean or null, if not found
                *********************************************************/

                   if (args.length!=2)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args; usage: value = BSF( " +
                                "'"+args[0]+"', beanName )");
                   }

                   Object tmp = null;
                   tmp=lookupBean(this, args[1]);
// System.err.println(" /// "+this+" - LOOKUP_BEAN: args[1]=["+args[1]+"], after lookupBean=["+tmp+"]");
                   if (tmp!=null)
                   {
                      return makeString4Rexx(this, tmp);
                   }
               }
          break;
     // ==================================================================


           case LOAD_CLASS         :
                   {
                   /* ********************************************************
                    * object = BSF( 'loadClass', JavaClassName )
                    *
                    * - JavaClassName: the fully qualified name of the Java class to load
                    * - returns:       the String rendering of the Java class object or null, if not found
                    *********************************************************/

                       if (args.length!=2)
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                    "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args; usage: value = BSF( " +
                                    "'"+args[0]+"', JavaClassName )");
                       }

                       Object tmp=null;

                       try
                       {
                           // tmp = Thread.currentThread().getContextClassLoader().loadClass(args[1]);
                           // rgf 20070918: EngineUtils now applies new class loader lookup
                           // tmp=EngineUtils.loadClass(mgr, args[1]); // ---rgf, 20070918
                           tmp=RexxReflectUtil.loadClass(this, choice.getMixedCase(), args[1]);
                           if (tmp==null)  // rgf, 2008-06-05
                           {
                               // throw (new ClassNotFoundException ("class ["+args[1]+"] not found"));
                               // throw (new ClassNotFoundException ("java.lang.ClassNotFoundException: "+args[1]));
                               throw (new ClassNotFoundException (args[1]));
                               // throw (new ClassNotFoundException ());
                           }
                       }
                       // catch (ClassNotFoundException e)
                       // {
                       //     throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                       //              "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": class '"+args[1]+"' not found!");
                       // }
                       catch (Exception e)
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                 // "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": class '"+args[1]+"', threw exception: ["+e.getLocalizedMessage()+"]");
                                 "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": class '"+args[1]+"', threw exception: ["+e.toString()+"]"
                                 , e  // rgf, 2011-06-04: supply Exception object
                                 );
                           // "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": class ["+args[1]+"], threw exception: ["+e.getLocalizedMessage()+"]");
                       }

                       if (tmp!=null)
                       {
                           return makeString4Rexx(this, tmp);
                       }
                   }
              break;
         // ==================================================================



           case RAW_REGISTER_BEAN  :     // 2008-08-28, ---rgf: pass-through for BSF manager's register Bean
                   {
                   /* ********************************************************
                    * object = BSF( 'rawRegisterBean', beanName, object )
                    *
                    * - beanName    - a string determining the index value to be used
                    *
                    * - object      - the object to be stored in the BSF registry
                    *
                    * - returns: beanName,
                    *
                    * Remarks: this subfunction will replace (!) any existing object in BSF
                    *          registry with the passed in one!
                    *
                    *********************************************************/
                       final boolean bDebug=false;

                       if (args.length!=3)
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                    "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args; usage: value = BSF( " +
                                    "'"+args[0]+"', beanName, object )");
                       }

                       // get Java value for object, register this with the BSF manager,
                       // register it with our reference count mechanism and return it

                       Object oJava=convFromRexx(args[2]);  // get Java null or Java object from BSF registry, String else

if (bDebug)
{
    System.err.println("---RexxAndJava, subfunction: args[0]=["+args[0]+"]: args[1]=["+args[1]+"]"+
                       ", args[2]=["+args[2]+"]<==>oJava=["+oJava+"]/oJava.getClass()=["+(oJava==null ? null : oJava.getClass())+"]");
}
//                       return RAJReg.rawRegisterBean(args[1], oJava, bsfPrefixReturnValue, rii_ID);
                       return rawRegisterBean(args[1], oJava);

                   }

         // ==================================================================




          case POLL_EVENT_TEXT    :
                  {
                      if (!eventDeprecationWarningAlreadyGiven)
                      {
                          // since 2018-02-17
                          System.err.println("RexxAndJava: Deprecation warning: the (old asynchroneous) BSF4ooRexx \"event\" related subfunctions"
                                             + " \"[addEventListener,pollEventText,postEventText]\""
                                             + " may be removed sometimes in the future, please change the Rexx"
                                             + " program using this outdated subfunction as soon as possible!");
                          eventDeprecationWarningAlreadyGiven=true;    // do not show this warning anymore in this run
                      }
                  /* ********************************************************
                   * call BSF 'pollEventText' [timeout]
                   *
                   * timeout: time in msec to wait for receiving an eventText
                   *          before returning to Rexx (this way using Java's
                   *          locking mechanism and waiting without a busy loop)
                   *********************************************************/
                      if(args.length>2) // 2009-06-20, rgf: added as Mr. Michael Lex (student@WU Vienna) found this as a bug in his work on TestUnits for BSF4ooRexx
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: value = BSF( " +
                              "'"+args[0]+"'[, timeout])");
                      }

                      long maxWait=0;           // wait forever
                      if (args.length>1)
                      {
                          maxWait=Long.parseLong(args[1]); // get maxWaitTime

                          if (maxWait<0L)       // illegal value ?
                          {
                              throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                       "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": 'timeout' argument value ["+maxWait+"] must not be negative");
                          }
                      }

                      try
                         {
                            return makeString4Rexx(this, eventTextList.get(maxWait));
                         }
                      catch (java.lang.InterruptedException e)
                         {
//                            e.printStackTrace(System.err);
                           throw new BSFException (BSFException.REASON_EXECUTION_ERROR,
                                    "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" threw ["+e.toString()+"], hence aborting..."
                                    , e  // rgf, 2011-06-04: supply Exception object
                                    );
                         }
                  }
        // ==================================================================

          case POST_EVENT_TEXT    :
                  {
                      if (!eventDeprecationWarningAlreadyGiven)
                      {
                          // since 2018-02-17
                          System.err.println("RexxAndJava: Deprecation warning: the (old asynchroneous) BSF4ooRexx \"event\" related subfunctions"
                                             + " \"[addEventListener,pollEventText,postEventText]\""
                                             + " may be removed sometimes in the future, please change the Rexx"
                                             + " program using this outdated subfunction as soon as possible!");
                          eventDeprecationWarningAlreadyGiven=true;    // do not show this warning anymore in this run
                      }
                  /* ********************************************************
                   * call BSF 'postEventText', eventText [, priority]
                   *
                   * eventText: eventText to be added to the "eventTextList"
                   * priority:  priority level, 0=low, 1=normal (default), 2=high ("alarm level")
                   *********************************************************/
                      if(args.length>3)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: value = BSF( " +
                              "'"+args[0]+"', eventText [, priority])");
                      }

                      int priority=1;     // default to normal priority

                      if (args.length==3) // priority given ?
                      {
                         priority=Integer.parseInt( args[2] );
                         if (priority<0 || priority>2) priority = 1;
                      }
                      eventTextList.put((Object) args[1], priority);
                      // return args[1];
                      return makeString4Rexx(this, args[1]);
                  }

        // ==================================================================


          case REGISTER_BEAN             :
          case REGISTER_BEAN_STRICT      :
                  {
                      final boolean bDebug=  // true;  // if true, show debug infos
                                            false;

                      if (choice==REGISTER_BEAN)
                      {
                          /* ********************************************************
                           * beanName = BSF( 'registerBean', beanName, beanType [, arg]... )
                           *
                           * - beanName: the bean's name, optional
                           * - beanType: the bean's type
                           * - arg: the argument's value
                           *********************************************************/
                          if (args.length<3)
                          {
                              throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                       "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: beanName=BSF( " +
                                      "'"+args[0]+"', [beanName], beanType [, argType, arg]... )");
                          }
                      }
                      else
                      {
                          /* ********************************************************
                           * beanName = BSF( 'registerBean', beanName, beanType [, argType, arg]... )
                           *
                           * - beanName: the bean's name, optional
                           * - beanType: the bean's type (class object or fully qualified class name
                           * - argType: the type of a constructor argument
                           * - arg: the argument's value
                           *********************************************************/

                          if((args.length<3) || ((args.length-3)%2!=0))
                          {
                              throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                       "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: beanName=BSF( " +
                                      "'"+args[0]+"', [beanName], beanType [, argType, arg]... )");
                          }
                      }

                      // rgf, 2018-02-17, new reflection code

// if (args[2]!=null && args[2].equals("org.apache.bsf.BSFManager")) System.err.print("("+java.util.Arrays.deepToString(args)+")");
if (args[2]!=null && args[2].equals("java.lang.Class")) System.err.print("("+java.util.Arrays.deepToString(args)+")");

                      RexxReflectUtil rru=new RexxReflectUtil(this, choice, args);

                      if (bDebug) System.err.println(this+": ---rgf-debug: "+rru+": "+rru.debugString());

// System.err.println("\n\n/// RAJ, l# 4102, choice=["+choice+"] - before rxReflector.reflect(rru) // args.length=["+args.length+"], args=\""+Arrays.deepToString(args)+"\"");
                      rxReflector.reflect(rru);
// System.err.println("\n\n/// RAJ, l# 4104, choice=["+choice+"] - AFTER  rxReflector.reflect(rru) // args.length=["+args.length+"], args=\""+Arrays.deepToString(args)+"\"");

                      if (rru.success)
                      {   // if the user supplied a beanName, use it

                          String beanName=(rru.beanName==null ? makeBeanName(this, rru.result) : rru.beanName);

                          if (bDebug) System.err.println("... RexxAndJava: choice=["+choice+"], using beanName=["+beanName+"] to store rru.result=["+rru.result+"]");
                          return registerBean(this, beanName, rru.result);
                      }

                      // no matching Constructor object found
                      if (rru.throwable != null)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": "+
                                   "\n\tbean:  ["+truncObject(rru.bean,65)+"] type: ["+rru.beanClz+"]"+
                                   "\n\tclass: ["+args[2]+"], no matching constructor found, cannot create the Java object",
                                rru.throwable);       // supply the Throwable from trying to invoke while searching for a Method
                      }

                      throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                               "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": "+
                               "\n\tbean:  ["+truncObject(rru.bean,65)+"] type: ["+rru.beanClz+"]"+
                               "\n\tclass: ["+args[2]+"], no matching constructor found, cannot create the Java object"
                               );

                  }

        // ==================================================================

          case UNBOX :  // rgf, 2019-01-07
                  {
                  /* ********************************************************
                   * call BSF 'unbox', beanName
                   *
                   * - beanName: the bean to unbox
                   *
                   * returns the unboxed value as a string or null, if value is not a boxed value
                   *
                   *********************************************************/
                      final boolean bDebug= // true;    // if true, show debug infos
                                           false;

                      if (args.length!=2)
                      {
if (bDebug) System.err.println("RexxAndJava()::UNBOX(): PANIC ! args.length!=2, instead: ["+(args==null? null : args.length)+"]!");
                              throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                       "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: call BSF " +
                                  "'"+args[0]+"', beanName; received Rexx arguments=\""+Arrays.deepToString(args)+"\"");
                      }

                      Object obj=lookupBean(this, args[1]); // try to fetch Java object from registry

                      if(obj==null)       // not in BSFRegistry, cannot be a boxed value then, return argument unchanged
                      {
                          return makeString4Rexx(this, null);   // indicate we have not unboxed the value
                      }

                      Class clz=obj.getClass();
                      if (clz==Boolean.class)
                      {
                          return makeString4Rexx(this, ((Boolean)obj).booleanValue() ? "1" : "0" );   // return Rexx truth values (strings)
                      }

                      if (   clz==Integer.class
                             || clz==Byte.class
                             || clz==Float.class
                             || clz==Long.class
                             || clz==Double.class
                             || clz==Short.class
                             || clz==String.class
                             || clz==Character.class
                      )
                      {
                          return makeString4Rexx(this, obj.toString()); // return String value
                      }

                      return makeString4Rexx(this, null);   // indicate we have not unboxed the value
                  }

        // ==================================================================

          case UNREGISTER_BEAN    :
                  {
                  /* ********************************************************
                   * call BSF 'unregisterBean', beanName
                   *
                   * - beanName: the bean to unregister
                   *
                   *********************************************************/
                      {
                          final boolean bDebug= // true;    // if true, show debug infos
                                                false;

                            // 2015-08-03, rgf
                          if (args.length!=2)
                          {
if (bDebug) System.err.println("RexxAndJava()::UNREGISTER_BEAN(): PANIC ! args.length!=2, instead: ["+(args==null? null : args.length)+"]!");
                              throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                       "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: call BSF " +
                                  "'"+args[0]+"', beanName; received Rexx arguments=\""+Arrays.deepToString(args)+"\"");
                          }

if (bDebug) System.err.println("RexxAndJava()::UNREGISTER_BEAN(): a) about to unregister=["+args[1]+"]");

                          int intRefCount=unregisterBean(args[1]);  // 2018-02-23, rgf: changed to return refCount

if (bDebug) System.err.println("RexxAndJava()::UNREGISTER_BEAN(): b) unregister=["+args[1]+"], left refCount="+intRefCount);

                          return (bsfPrefixReturnValue ? STRING_INDICATOR_PREFIX : "")+intRefCount;
                      }
                  }
        // ==================================================================


          case SET_REXX_NULL_STRING :
                  {
                  /* ********************************************************
                   * call BSF 'setRexxNullString', newString
                   *
                   * - newString: string to use for indicating "null" to/by Rexx
                   *              (default is the string ".NIL" in field "null4Rexx"
                   *********************************************************/
                      if(args.length!=2 || args[1]==null)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid arguments; usage: call BSF " +
                              "'"+args[0]+"', newString");
                      }
                      null4Rexx=args[1];        // set new value
                      // return args[1];
                      return makeString4Rexx(this, args[1]);
                  }
        // ==================================================================


           case BSF_PREFIX_RETURN_VALUE :
                   {
                   /* ********************************************************
                    * object = BSF( 'bsfPrefixReturnValue'[, 0|1] )
                    *
                    * "0" or "1" - if false, do not prefix the returned strings with
                    *              type indicators; else prepend them
                    *
                    * - returns: - the actual value of this setting
                    *********************************************************/

                       if (args.length>2)
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                    "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args;\nusage: value = BSF( " +
                                   "'"+args[0]+"' [, 0 | 1 ] )");
                       }

                       if (args.length==2)   // no argument given, return current setting
                       {
                           try  // convert to short, if not "0", then true, false else
                           {
                               bsfPrefixReturnValue=((Short.decode(args[1].trim()).shortValue())!=0);
                           }
                           catch (Exception e)
                           {
                               throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                        "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid argument ["+args[1]+"];\nusage: value = BSF( " +
                                        "'"+args[0]+"' [, 0 | 1] ), exception thrown: ["+e.toString()+"]"
                                        , e  // rgf, 2011-06-04: supply Exception object
                                        );
                           }
                       }

                       // return makeString4Rexx( this, new Boolean(bsfPrefixReturnValue) );
                       return makeString4Rexx( this, (bsfPrefixReturnValue ? Boolean.TRUE : Boolean.FALSE) );

                   }
        // ==================================================================
          case CARRY_OUT_SYSTEM_EXIT:
              {
              /* ********************************************************
               * object = BSF( 'carryOutSystemExit'[, 0|1] )
               *
               * "0" or "1" - if false, then the "exit" subfunction is not carried out
               *
               * - returns: - the actual value of this setting
               *********************************************************/

                  if (args.length>2)
                  {
                      throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                               "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid # of args;\nusage: value = BSF( " +
                              "'"+args[0]+"' [, 0 | 1 ] )");
                  }

                  if (args.length==2)   // no argument given, return current setting
                  {
                      try  // convert to short, if not "0", then true, false else
                      {
                          carryOutSystemExit=((Short.decode(args[1].trim()).shortValue())!=0);
                      }
                      catch (Exception e)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" invalid argument ["+args[1]+"];\nusage: value = BSF( " +
                                   "'"+args[0]+"' [, 0 | 1] ), exception thrown: ["+e.toString()+"]"
                                   , e  // rgf, 2011-06-04: supply Exception object
                                   );
                      }
                  }

                  // return makeString4Rexx( this, new Boolean(carryOutSystemExit) );
                  return makeString4Rexx( this, (carryOutSystemExit ? Boolean.TRUE : Boolean.FALSE) );

              }
   // ==================================================================


          case SLEEP :  // meant for Regina and other Rexxes which don't have a SysSleep() by default
                  {
                  /* ********************************************************
                   * call BSF 'sleep', time2sleep
                   *
                   * - time2sleep: decimal number of seconds to sleep, e.g. '10' (ten seconds),
                   *               '0.5' (half a second), '0.01' (1/100 second), '600' (10 minutes)
                   *********************************************************/

                      if(args.length!=2 || args[1]==null)
                      {
                          throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid arguments; usage: call BSF " +
                              "'"+args[0]+"', time2sleep");
                      }

                      long sleepTime = 0l;

                      try {   // convert received string into a long (rounded up)
                              sleepTime = (long) ((new java.math.BigDecimal(args[1])).doubleValue()*1000+0.5d);
                          }
                      catch (Exception e)
                          {
                              throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                   "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": argument 'time2sleep', value '"+args[1]+"' not numeric, exception thrown: ["+e.toString()+"]"
                                   , e  // rgf, 2011-06-04: supply Exception object
                                   );
                          }

                      Thread thisThread = Thread.currentThread(); // get current Thread
                      try
                      {
                         thisThread.sleep( sleepTime );   // sleep the indicated time
                      }
                      catch (Exception e)
                      {
                         e.printStackTrace();
                      }

                      break;
                  }




        // ==================================================================

           case WRAP_ENUMERATION_OBJECT:
               /*********************************************************
                * value = BSF( 'wrapEnumeration', arrayObject)
                *
                * - arrayObject:   array to be worked upon
                *********************************************************/
               {

                   Object enumObj = null;
                   enumObj=lookupBean(this, args[1]);

                   if (enumObj == null)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" object ["+args[1]+"] not registered!");
                   }

                   if (!(enumObj instanceof Enumeration))
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" object ["+args[1]+"] does not have the 'Enumeration' interface implemented!");
                   }
                   return makeString4Rexx(this, new EnumerationWrapper( (Enumeration) enumObj) ); // wrap the object and return it to Rexx
               }




               // ==================================================================

           case REXX_HALT :
                   {
                   /* ********************************************************
                    * call BSF 'haltThread', tid
                    *
                    * - tid: BSFGetTID()-value; if "0" all Rexx thread instances
                    *        are halted/terminated
                    *********************************************************/
                       if(args.length!=2 || args[1]==null)
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                    "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid arguments; usage: call BSF " +
                               "'"+args[0]+"', tid");
                       }

                        // now halt given thread
                       return makeString4Rexx(this, ""+jniRexxSetHalt(args[1]));
                   }


        // ==================================================================
        // ---rgf, 2014-03-29

           case ENV_GET:
           case ENV_SET:
               /*********************************************************
                * value = BSF( 'getEnv', envName)
                * value = BSF( 'setEnv', envName, newValue )
                        -- remove environment variable:
                * value = BSF( 'setEnv', envName) or
                * value = BSF( 'setEnv', envName, null)
                *
                * - arrayObject:   array to be worked upon
                *********************************************************/
               {
                   final int GET_ENVIRONMENT_VARIABLE=1;
                   final int SET_ENVIRONMENT_VARIABLE=2;

                   if ( choice==ENV_GET && (args.length!=2 || args[1]==null ) )
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid arguments; usage: call BSF " +
                           "'"+args[0]+"', envName");
                   }
                   else if (args.length<2 || args.length>3 || args[1]==null )
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid arguments; usage: call BSF " +
                           "'"+args[0]+"', envName [, newValue=.nil]");
                   }

                   String res=null;

                   if (choice==ENV_GET)
                   {
                       res=jniProcEnvironment(GET_ENVIRONMENT_VARIABLE, args[1], null);    // get current value for environment variable
                   }

                   if (choice==ENV_SET)     // set or unset
                   {
                       res=jniProcEnvironment(SET_ENVIRONMENT_VARIABLE, args[1], args.length==2 ? null : args[2]);
                   }

                   return makeString4Rexx( this, res );           // wrap the object and return it to Rexx
               }



               // ==================================================================

                                // 2009-10-17, ---rgf
           case KUDOS     :     // "Easter-egg": return a string of people who have helped the cause of "BSF4ooRexx" one way or the other
                   {
                   /* ********************************************************
                    * call BSF 'kudos'
                    *
                    *********************************************************/
                       if(args.length!=1)
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                    "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid number of arguments");
                       }

                       String kudos=
                           "Ahammer, Andreas"                       + "\n" +
                           "Augustin, Walter"                       + "\n" +
                           "Baginski, Adrian"                       + "\n" +    // 2016-08-14, rgf: .NET/CLR nutshell examples, 2017: JavaFX, ooRexxTryFX.rxj
                           "Barmwater, Gil"                         + "\n" +
                           "Beck, Andreas"                          + "\n" +
                           "Blasco, Josep Maria"                    + "\n" +    // 2024-06-20, rgf: testing, reported handler related erros
                           "Burger, Martin"                         + "\n" +
                           "Cowlishaw, Mike F."                     + "\n" +
                           "Davis, Chip"                            + "\n" +
                           "Dunkley, Paul"                          + "\n" +    // 2016-08-14, rgf: created s390x version of BSF4ooRexx.cc
                           "Dujis, Erik"                            + "\n" +
                           "Dycks, Tony"                            + "\n" +    // 2020-12-18, rgf: created arm32 and aarm64 native libraries
                           "Egli, R\u00e4tus"                       + "\n" +
                           "Faucher, Jean-Louis"                    + "\n" +
                           "Flatscher, Alice R."                    + "\n" +
                           "Flatscher, Daniel A."                   + "\n" +
                           "Flatscher, Michael B."                  + "\n" +
                           "Fosdick, Howard"                        + "\n" +
                           "Frysak, Josef"                          + "\n" +
                           "Gerger, Eva"                            + "\n" +    // 2016-08-24, rgf: tester (samples)
                           "Gmeiner, Michael"                       + "\n" +
                           "Gundacker, Dominik"                     + "\n" +
                           "G\u00f6rlich, Gerhard"                  + "\n" +
                           "Gro\u00dfe-Coosmann, Florian"           + "\n" +
                           "Hahnekamp, Rainer"                      + "\n" +
                           "Heinisch, Florian"                      + "\n" +
                           "Hesse, J\u00fcrgen"                     + "\n" +      // 2011-01-24, rgf
                           "Hessling, Mark"                         + "\n" +
                           "Hinz, Michael"                          + "\n" +
                           "Hoisl, Bernhard"                        + "\n" +
                           "Jansen, Ren\u00e9"                      + "\n" +
                           "Kalender, Peter"                        + "\n" +
                           "Kauril, Michael"                        + "\n" +
                           "Ke\u00dfler, Matthias"                  + "\n" +
                           "Lex, Michael"                           + "\n" +
                           "M\u00e4rker, Kurt"                      + "\n" +
                           "Marks, Brian"                           + "\n" +
                           "Matthiesen, Faber"                      + "\n" +
                           "McGuire, Rick"                          + "\n" +
                           "Miesfeld, Mark"                         + "\n" +
                           "M\u00fcller, Franz"                     + "\n" +
                           "Moldaschl, Markus"                      + "\n" +
                           "Nash, Simon"                            + "\n" +
                           "Paar, Manuel"                           + "\n" +      // 2011-01-24, rgf
                           "Pachl, Walter"                          + "\n" +
                           "Peedin, Lee"                            + "\n" +
                           "Perushin, Igor"                         + "\n" +    // 2018-10-11, rgf: created the ARM-32 version (for Raspberry Pi)!
                           "Pezerovic, Edin"                        + "\n" +
                           "Prem, Matthias"                         + "\n" +
                           "Raffel, Manuel"                         + "\n" +    // 2016-08-24, rgf: original author of .NET-support with CLR.CLS, oorexx.net.*
                           "Ratliff, Matt"                          + "\n" +
                           "Realfsen, \u00c5smund"                  + "\n" +
                           "Reindorf, Julian"                       + "\n" +    // 2016-08-24, rgf: testers (samples)
                           "Richard, Pierre G."                     + "\n" +
                           "Ruggles, David"                         + "\n" +
                           "Sauer, Ralph"                           + "\n" +
                           "Schmid, Stefan"                         + "\n" +
                           "Scholz, Nicole"                         + "\n" +
                           "Skelly, Bruce"                          + "\n" +    // help for the Mac installer that includes ooRexx since 2010
                           "Small, John"                            + "\n" +
                           "Sonnemans, Freddy"                      + "\n" +
                           "Spanberger, David"                      + "\n" +
                           "Specht, Tobias"                         + "\n" +
                           "St\u00f6hr, Dennis R."                  + "\n" + // 2011-01-24, rgf
                           "Taylor, Pam"                            + "\n" +
                           "Turner, Bill"                           + "\n" + // 2011-04-10, rgf
                           "Waglechner, Christoph"                  + "\n" +
                           "Wilson, Gray (artwork: graphics, icons)"+ "\n" +
                           "Winkler, Till"                          + "\n" + // 2022-12-31, rgf
                           "Woehr, Jack"                            + "\n" +
                           "Wolfers, Jon (Sahananda)"
                           ;

                        // now halt given thread
                       return makeString4Rexx(this, ""+kudos);
                   }

      // ==================================================================

       case GET_RII_ID  :
               {
               /* ********************************************************
                * call BSF 'get_rii_id'
                * returns the this RII_ID value ("Rexx Interpreter Instance", a string)
                * rgf, 2015-08-03
                *********************************************************/

                   if (args.length > 1)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+" does not expect any argument!");
                   }

                   return makeString4Rexx(this, get_rii_ID());    // return this instance
               }


      // ==================================================================

       case INCREASE_REF_COUNTER :
               {
               /* ********************************************************
                * call BSF 'increaseRefCounter'*, 'beanName'
                *
                *- beanName: the bean's name, mandatory, must exist
                * returns the new refcount
                * rgf, 2015-08-04
                *********************************************************/

                   final boolean bDebug= // true;    // if true, show debug infos
                                         false;

                   if (args.length<2)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: newRefCount=BSF( " +
                               "'"+args[0]+"', beanName");
                   }

                   String beanName=args[1];

                   String str="";

                   //rgf20220720 synchronized (lockRajRegistry)
                   {
                       RAJBean bean=rajRegistry.get(beanName);   // get bean
                       {
                           if (bean==null)       // no bean stored by that name
                           {
                               throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                        "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": beanName ["+beanName+"] not in registry, cannot increase refCounter!");
                           }

                           bean.refCount+=1;                      // increase refcount
                           str= makeString4Rexx(this, bean.refCount);   // return new refcount for the bean

if (bDebugRefCounter)
{
     if (bean.refCount>bDebugRefCounterThreshold || rajRegistryToWatch.get(beanName)!=null)
     {
System.err.println("//++// increaseRefCounter/(registerBean), RAJBean: "+bean+" \\\\++\\\\");

        if (rajRegistryToWatch.get(beanName)==null)
        {
            rajRegistryToWatch.put(beanName, bean);
        }
     }
}
                       }

                   }

                   return str;
                   // return makeString4Rexx(bean.refCount);   // return new refcount for the bean

               }


               // ==================================================================

           case REXX_REFLECT_OBJECT:        // returns the currently used RexxReflectInterface object
               // rgf, 2018-02-17
               {
                   /*********************************************************
                    * value = BSF( 'rexxReflectObject'[, javaVersion])
                    *
                    * - if no arg, simply returns the current rxReflector object
                    *
                    * - "javaVersion" arg must be a number indicating the Java version to support (>=6);
                    *    this will allow to change the reflector object to use e.g. RexxReflectJava6 on
                    *    later versions of Java that might be using a later RexxReflectInterface (e.g. deploying
                    *    MethodHandle and such);
                    *
                    *    in order to not allow security breaches, the information whether a public lookup object
                    *    was used (reducing access rights to java.lang.Object) will be retained in RexxReflectJava6,
                    *    such that changing it to higher versions later, will not allow to get the rights
                    *    of this package/class by making sure that publicLookup is used then
                    *
                    *********************************************************/
                   {

                       if ( args.length>2 )
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                    "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: \"rxReflector=bsf.wrap(BSF(" +
                                   "'"+args[0]+"'[, javaVersionToSupport]))\"");
                       }

                       if (args.length==2)  // replace current rxReflect with a new one (for debugging)
                       {
                           int javaVersionToSupport=0;
                           try
                           {
                               javaVersionToSupport=Integer.valueOf(args[1]);   // get integer value
                           }
                           catch (Exception e)
                           {
                               throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                        "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": argument 'javaVersion' is not a whole number, received: \""+args[1]+"\"");
                           }

                           if (javaVersionToSupport<6)
                           {
                               throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                        "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": argument 'javaVersion' must be 6 or higher, received: \""+args[1]+"\"");
                           }

                           createRexxReflectJava(javaVersionToSupport);     // create new RexxReflectInterface object
                       }

                       return makeString4Rexx( this, rxReflector ); // wrap the RexxReflect object and return it to Rexx
                   }

               }

           case GET_BEAN_REFCOUNT :         // 2018-02-23, debugging aid
               {
               /* ********************************************************
                * call BSF 'getBeanRefCount', beanName
                *
                * - beanName: the bean to unregister
                *
                * - returns the current reference count or -1, if not in registry
                *
                *********************************************************/
                   if (args.length!=2)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: call BSF " +
                           "'"+args[0]+"', beanName; received Rexx arguments=\""+Arrays.deepToString(args)+"\"");
                   }

                   int intRefCount=getBeanRefCount(args[1]);    // get reference count for the bean

                   return (bsfPrefixReturnValue ? STRING_INDICATOR_PREFIX : "")+intRefCount;
               }


           case TEST_PING         :         // 2018-02-25, debugging (test and timing) aid
               {
               /* ********************************************************
                * call BSF 'testPing' [, repetitions[, RexxProxy, messageName]
                *
                * - repetitions: optional, if no RexxProxy and messageName given, the number of repetitions to call jniTestPing()
                *
                * - RexxProxy:   if given, repetitions and messageName must be given as well; denotes the Rexx object
                *                to send the message repetitions times

                * - messageName: the Rexx message to send to the RexxProxy
                *
                *********************************************************/
                   if (args.length>4 || args.length==3)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: \"call BSF " +
                           "'"+args[0]+"' [, repetitions [, RexxProxy, messageName]]\"); received Rexx arguments=\""+Arrays.deepToString(args)+"\"");
                   }

                   if (args.length==1)      // just return, invocations get measured
                   {
                       return makeString4Rexx(this, null);  // we return null (in this case: nothing)
                   }

                   int repetitions=-1;
                   NumberFormatException nfe=null;
                   try {
                       repetitions=Integer.parseInt(args[1]);   // fetch integer value
                   } catch (NumberFormatException e)
                   {
                       nfe=e;       // save Throwable
                   }

                   if (nfe!=null || repetitions<1)
                   {
                       String info="BSF4ooRexx subfunction "+'"'+args[0]+'"'+": argument # 2 must be a positive, whole number, received=\""+args[1]+"\""
                                   +"usage: \"call BSF '"+args[0]+"' [, repetitions [, RexxProxy, messageName]]\")"
                                   +"; received Rexx arguments=\""+Arrays.deepToString(args)+"\"";

                       if (nfe!=null)
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT, info, nfe);    // supply Exception object
                       }
                       else
                       {
                           throw new BSFException (BSFException.REASON_INVALID_ARGUMENT, info);
                       }
                   }

                   if (args.length==2)      // o.k., only calls into jniTestPing() desired, carry them out
                   {
                       for (int i=0; i<repetitions; i++)
                       {
                           jniTestPing();   // call into native code
                       }
                       return makeString4Rexx(this, null);  // we return null (in this case: nothing)
                   }

                   RexxProxy rp=(RexxProxy) lookupBean(this, args[2]);  // fetch RexxProxy object
                   if (rp==null)            // not found
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": unknown argument # 3 \""+args[3]+"\" (this RexxProxy not found in registry); usage: \"call BSF " +
                           "'"+args[0]+"' [, repetitions [, RexxProxy, messageName]]\"); received Rexx arguments=\""+Arrays.deepToString(args)+"\"");
                   }

                   String messageName=args[3];
                   if (messageName==null)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": argument # 4 must not be null (the message to send to the Rexx object wrapped in the supplied RexxProxy object);"
                                       +"usage: \"call BSF '"+args[0]+"' [, repetitions [, RexxProxy, messageName]]\"); received Rexx arguments=\""+Arrays.deepToString(args)+"\"");
                   }
                        // send the Rexx message to the Rexx object
                   for (int i=0; i<repetitions; i++)
                   {
                       rp.sendMessage0(messageName);
                   }
                   return makeString4Rexx(this, null);  // we return null (in this case: nothing)
               }

           // ==================================================================

           case SIMPLE_EXECUTE_ARGUMENT:    // 2022-08-06:
               {
               /* ********************************************************
                * call BSF 'simpleExecute', [rexxCode], [rexxArgument]
                *
                * creates a new RII, runs the code (if supplied) with the
                * string argument (if supplied) and terminates the RII again
                *
                * - rexxCode: optional, the code to run
                *
                * - rexxArgument: optional, the single string argument
                *
                * - returns a string value of whatever the rexx code returns
                *
                *********************************************************/
                   if (args.length>3)
                   {
                       throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                                "BSF4ooRexx subfunction "+'"'+args[0]+'"'+": invalid # of args; usage: call BSF " +
                           "'"+args[0]+"', [rexxCode], [rexxArgument]; received Rexx arguments=\""+Arrays.deepToString(args)+"\"");
                   }

                   String rexxCode=null, rexxArgument=null;
                   if (args.length>1)
                   {
                       rexxCode=args[1];
                   }
                   if (args.length>2)
                   {
                       rexxArgument=args[2];
                   }
                   String res=jniExecuteSimpleProcedureOnOwnRII(rexxCode, rexxArgument);

                   // return (bsfPrefixReturnValue ? STRING_INDICATOR_PREFIX : "")+strRes;

                   return makeString4Rexx( this, res );           // wrap the object and return it to Rexx

               }



        // ==================================================================
          default:
                  throw new BSFException (BSFException.REASON_EXECUTION_ERROR,
                           "'"+args[0]+"': unknown function name (no such function implemented).");
       }
        // ==================================================================

        return makeString4Rexx(this, null);
    }



     // rgf, 2005-05-07
    /** Returns <code>printStackTrace()</code> as a <code>String</code>.
     *
      * @param e an Exception object.
      * @return  a String
    */
    private String getPrintStackAsString(Exception e)
    {
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       PrintStream           ps   = new PrintStream(baos);
       e.printStackTrace(ps);
       return baos.toString();
    }


    // rgf, 2006-02-15
    /** Invokes method and makes sure that any public method will get successfully invoked.
     *
     * @param m method object to use for invocation
     * @param o object for which the method should get invoked
     * @param params Object[] with parameters to supply
     * @return the result of the method invocation
     */
    Object invokeMethod (Method m, Object o, Object [] params) throws IllegalAccessException, InvocationTargetException
    {
        try
        {

// System.err.println("[[[ ---> RAJ.invokeMethod: o=["+o+"], o.toString()=["+o.toString()+"], method="+m.toString()+"] <--- ]]]");

            return m.invoke(o, params);
        }
        catch (IllegalAccessException e)    // maybe an IllegalAccessException?
        {
            // if ( // bMethodHasSetAccessible &&
            //     Modifier.isPublic(m.getModifiers()) )   // if a public method allow access to it
            // {
                m.setAccessible(true);      // allow unconditional access
                return m.invoke(o, params);
            // }
            // throw e;    // re-throw exception
        }
    }






    /** Converts the string from Rexx to the indicated type. If
      * a type 'O' is indicated and the value for it is an empty string,
      * then <code>null</code> is returned for it.

      * @param type one of
                    &quot;<strong>BO</strong>olean&quot; (i.e. '0' or '1'),
                    &quot;<strong>BY</strong>te&quot;,
                    &quot;<strong>C</strong>har&quot;,
                    &quot;<strong>D</strong>ouble&quot;,
                    &quot;<strong>F</strong>loat&quot;,
                    &quot;<strong>I</strong>nt&quot;,
                    &quot;<strong>L</strong>ong&quot;,
                    &quot;<strong>O</strong>bject&quot; (Object, i.e. a registered bean),
                    &quot;<strong>SH</strong>ort&quot;, and
                    &quot;<strong>ST</strong>ring&quot;.

      * @param value the value from Rexx (a string) to be converted to the
               Java type.
      *
      * @return  the converted value.
      */

    Object convFromRexx(String type, String value) throws BSFException
    {
        final boolean bDebug=  // true;   // if true, show debug infos
                               false;

if (bDebug) System.err.println("RexxAndJava.convFromRexx(): type=\""+type+"\", value=\""+value+"\" value==null: \""+(value==null)+"\" null4Rexx=\""+null4Rexx+"\"");
        if (value==null) return null;

        if (type!=null && type.length()>0)
        {
             if (value.equals(null4Rexx))   // Rexx-String indicating "null" ?
                return null;

             if (Character.toUpperCase(type.charAt(0))=='O' )   // if 'Object', just return the object from the registry
             {
                 // no object indicated, hence return null
                 if (value.equals("")) return null;

                 Object tmp=lookupBean(this, value);

                 if (tmp==null){
                     throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
                         "Bean ["+value+"] not registered.");
                 }

                 return tmp;
             }
                // either strictly a String or a primitive type as indicated
             Object res=new RexxStrictArgument(this, type, value, true);

if (bDebug)
System.err.println("RexxAndJava.convFromRexx(): type=\""+type+"\", value=\""+value+"\" value==null: \""+(value==null)+"\" null4Rexx=\""+null4Rexx+"\"; returning --> ["+res+"]");
             return res;
         }

            // if we arrive here, we have a problem ...
         throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
             "RexxAndJava.convFromRexx(): unknown type \""+type+"\" or incompatible value \""+value+"\".");
    }




    /** Converts the string from the JNI to the indicated primitive/wrapper type, using
     *  Java's type indicators.

      * @param type one of
                    &quot;<strong>Z</strong>&quot; Boolean (i.e. '0' or '1'),
                    &quot;<strong>B</strong>te&quot;,
                    &quot;<strong>C</strong>har(acter)&quot;,
                    &quot;<strong>D</strong>ouble&quot;,
                    &quot;<strong>F</strong>loat&quot;,
                    &quot;<strong>I</strong>nt&quot;,
                    &quot;<strong>J</strong>&quot; Long, and
                    &quot;<strong>S</strong>hort&quot;.

      * @param value the value from Rexx (a string) to be converted to the
               Java type.
      *
      * @return  the converted value.
      */
    private Object convFromJNI(String type, String value) throws BSFException
    {
// System.err.println("convFromJNI(type=["+type+"], value=["+value+"])");
        if (value==null || value.length()==0) return null;

         switch (type.charAt(0))    // turn type into a char
         {

             case 'S':  // return new Short( value );   // Short
                        return Short.valueOf( value );  // Short

             // case 'I':  return new Integer      (value);
             case 'I':  return Integer.valueOf(value);
             // case 'C':  return new Character    (value.charAt(0));
             case 'C':  return Character.valueOf(value.charAt(0));

             case 'Z':    // Boolean
                        // return new Boolean( value.equals("1") || value.equalsIgnoreCase("true") );
                        if (value.equals("1") || value.equalsIgnoreCase("true"))
                        {
                            return Boolean.TRUE;
                        }
                        return Boolean.FALSE;

             // case 'B':  return new Byte( value );   // Byte
             case 'B':  return Byte.valueOf (value);   // Byte

             // case 'F':  return new Float        (value);
             case 'F':  return Float.valueOf(value);
             // case 'J':  return new Long         (value);
             case 'J':  return Long.valueOf (value);
             // case 'D':  return new Double       (value);
             case 'D':  return Double.valueOf(value);
         }
         throw new BSFException (BSFException.REASON_INVALID_ARGUMENT,
             "unknown return type ["+type+"], with value ["+value+"] (expecting the internal Java type indicator for primitives)");
    }




    /** Replaces a reference to a Java object with the Java object.
     *
     * @param value this String is used to look up the BSF registry. If an entry is found (a
     * Java object) it will get returned, if not (or the value is <code>null</code>) then
     * <code>null</code> is returned.
     *
     * @return the Java <code>object</code> stored in the BSF registry, <code>null</code> else
     **/
    // 20090514, ---rgf, turn to package scope
    Object convFromRexx(String value) throws BSFException
    {
        final boolean bDebug=  // true;
                               false;
         if (value==null) return null;

         if (value.equals(null4Rexx))   // Rexx-String indicating "null" ?
            return null;

         // Is this a reference to a Java object in the BSF registry?
         // If so, return Java object
         Object tmp=null;
         tmp=lookupBean(this, value);

         if (tmp==null) return value;
if (bDebug) System.err.println("RexxAndJava.convFromRexx(): value=\""+value+"\", bean=tmp=\""+tmp+"\".getClass()=\""+tmp.getClass()+"\".toString()=\""+tmp.getClass().toString()+"\"");

         return tmp;
    }


    /** Coerces the arguments from Rexx to the appropriate Java types.
     * @param funcArgs an <code>Object</code> array (actually the Rexx arguments of type
     *        <code>String</code>)
     * @param paramTypes an <code>Class</code> array, containing the Java class objects to which
     *        the Rexx arguments have to be converted to
     * <!-- (rgf, 2003-05-08) -->
     *  @return an array with the coerced arguments, if successful, <code>null</code> else.
     */
    // static Object [] coerceArgs(Object [] funcArgs, Class [] paramTypes)
    Object [] coerceArgs(Object [] funcArgs, Class [] paramTypes)
    {
        int k,
            nrArgs=funcArgs.length;

        final boolean bDebug=  // true;
                               false;

if (bDebug) System.err.println("\n---   ---   ---   ---   ---");

        Object [] coercedArgs = new Object [nrArgs];

        for (k=0; k<nrArgs;k++)
        {
if (bDebug) System.err.println("\tcoerceArgs() ---> k="+k+" (funcArgs.length="+funcArgs.length+
                                              ", paramTypes.length="+paramTypes.length+")");

if (bDebug) System.err.println("\t\tfuncArgs[k]=\""+funcArgs[k]+"\" ---> \""+paramTypes[k]+"\"");

            if (funcArgs[k]==null)    // assuming explicit null is o.k. in any case
            {
if (bDebug) System.err.println("\t           ) ---> k=\""+k+"\": null!");
                coercedArgs[k]=null;
            }

                // rgf, 2018-11-01, special case that a strict argument type is requested
            else if (funcArgs[k] instanceof RexxStrictArgument)
            {
                RexxStrictArgument rsa=(RexxStrictArgument) funcArgs[k];    // cast to proper class
if (bDebug)
   System.err.println("\t/-->/\tcoerceArgs(): RexxStrictArgument: paramTypes[k]=["+paramTypes[k]+", rsa=["+rsa
                       +"]: paramTypes[k] ("+paramTypes[k].toString()+")==rsa.classObject =["+(paramTypes[k]==rsa.classObject)+"]");
                if (paramTypes[k] != rsa.classObject)   // does not strictly equal the required class
                {
if (bDebug)
   System.err.println("\t/-->/\tcoerceArgs(): RexxStrictArgument: paramTypes[k]=["+paramTypes[k]+" != rsa.classObject=["+rsa.classObject+"] Not compatible, RETURNING NULL!");
                    return null;    // indicate not successful
                }
                coercedArgs[k]=rsa.value;
if (bDebug)
    System.err.println("\t/-->/\tcoercedArgs[k]: ["+coercedArgs[k]+"] <-- rsa.value=["+rsa.value+"] SUCCESS!");
                continue;
            }

                // rgf, 2005-06-18, special case found: an interface is given, that is available for String as well!
            else if ( paramTypes[k].isInterface()  || (!(funcArgs[k] instanceof String)))
            {

if (bDebug) System.err.print("\t           ) ---> k="+k+": an Object not a String in hand: funcArgs \""+
                                          funcArgs[k]+"\" to paramTypes \""+paramTypes[k]+"\", assignable?");
// rgf, 2005-10-32                if (!(paramTypes[k].isAssignableFrom (funcArgs[k].getClass()))) // not compatible, break
if (bDebug)
{
    if (paramTypes[k].isArray())
    {
        System.out.println("\n\t\t==> ==> \""+paramTypes[k]+"\": paramTypes[k].isArray=true, class=\""+paramTypes[k].getClass()+"\"");

        // System.out.println("\t\tgetLength(): "+((Array)paramTypes[k]).getLength());
        System.out.println("\t\t==> ==> \""+funcArgs[k]+"\": funcArgs[k].getClass()=\""+funcArgs[k].getClass()+"\"" );

        System.out.println("paramTypes[k] instanceof (String): "+paramTypes[k] instanceof String);
        System.out.println("funcArgs[k] instanceof (String):   "+funcArgs[k] instanceof String);
        try{
            ArrayWrapper paw=new ArrayWrapper(paramTypes[k]);
            ArrayWrapper faw=new ArrayWrapper(funcArgs[k]);

            System.out.println("paw=\""+paw+"\", dimensions="+paw.dimensions+", componentType=\""+paw.componentType+"\"");
            System.out.println("faw=\""+faw+"\", dimensions="+faw.dimensions+", componentType=\""+faw.componentType+"\"");
        }
        catch (Exception e)
        {
if (bDebug) System.err.println("\t            exception while trying to display paramTypes and funcArgs: e.toString()=("+e.toString()+")");
        }

    }
}

                if (!( ( (Class<?>)paramTypes[k]).isAssignableFrom (funcArgs[k].getClass()))) // not compatible, break
                {
                    // if (paramTypes[k].isPrimitive())
                    // rgf, 20100519 all primitive->wrappers get intercepted here: this allows to interchange primitive with matching wrapper types
                    if (
                          (paramTypes[k]==boolean.class  && funcArgs[k].getClass()==Boolean.class  ) ||
                          (paramTypes[k]==byte.class     && funcArgs[k].getClass()==Byte.class     ) ||
                          (paramTypes[k]==char.class     && funcArgs[k].getClass()==Character.class) ||
                          (paramTypes[k]==short.class    && funcArgs[k].getClass()==Short.class    ) ||
                          (paramTypes[k]==int.class      && funcArgs[k].getClass()==Integer.class  ) ||
                          (paramTypes[k]==long.class     && funcArgs[k].getClass()==Long.class     ) ||
                          (paramTypes[k]==float.class    && funcArgs[k].getClass()==Float.class    ) ||
                          (paramTypes[k]==double.class   && funcArgs[k].getClass()==Double.class   )
                       )
                    {
                        coercedArgs[k]=funcArgs[k];
            if (bDebug) System.err.println("\t           ) ---> k="+k+": successful coercion.");
                        continue;
                    }
if (bDebug) System.err.println(" NO ! (k="+k+")");

                    break;
                }
if (bDebug) System.err.println(" yes. (k="+k+")");

                coercedArgs[k]=funcArgs[k];
if (bDebug) System.err.println("\t           ) ---> k="+k+": successful coercion.");
                continue;
            }
            else
            {
                String tmpArg=(String) funcArgs[k];  // ---rgf, for {B|b}oolean coercion

                  // do we need a String, if so, we have it already!
                if (paramTypes[k]==String.class) {
                    coercedArgs[k]=funcArgs[k];
if (bDebug) System.err.println("\t           ) ---> k="+k+": successful coercion to String.");
                    continue;
                }

// ---> NetRexx coercion, if NetRexx.class is available <---
                 // do we need a netrexx.lang.Rexx instance?
                if (nlR_class!=null && paramTypes[k]==nlR_class) {
                    // try to create an instance of netrexx.lang.Rexx
                    try {
                        Class argClass[]={funcArgs[k].getClass()};  // determine class of argument
                        Constructor constr=((Class<?>)paramTypes[k]).getConstructor( argClass );

                        Object argRgf[]={funcArgs[k]};              // create argument array
                        coercedArgs[k]=constr.newInstance(argRgf);  // assign coerced object

if (bDebug) System.err.println("\t           ) ---> k="+k+": successful coercion to netrexx.lang.Rexx.");
                        continue;
                    }
                    catch (Exception e)
                    {

if (bDebug) System.err.println("\t            exception in NetRexx-branch: e.toString()=("+e.toString()+")");
                        ;
                    }
                }

                  // try to co-erce argument
                TypeConvertor cvtor = glob_tcr.lookup (String.class, paramTypes[k]);
                if (cvtor==null)   // no convertor found, break; look for another method
                {
if (bDebug)
System.err.println("\t           ) ---> k="+k+": no cvtor found! paramTypes[k]: \""+paramTypes[k]+"\")");
                    break;
                }


                    // BSF uses Boolean.valueOf() which is far too unrestricted !
                if (paramTypes[k]==boolean.class || paramTypes[k]==java.lang.Boolean.class)   // ---rgf, 2005-07-07: make sure Boolean are converted correctly
                {
if (bDebug)
System.err.println("\t  >>> >>>  checking for {B|b}oolean value!");
                    // ---rgf, 2006-05-29: be stricter than Java, only accept "0", "1", "false", "true", ".false" and ".true" as Boolean's
                    // String s=(String)funcArgs[k];   // coerce to a string

                    // if (tmpArg.equals("0") || tmpArg.equalsIgnoreCase(".FALSE") || tmpArg.equalsIgnoreCase("FALSE"))
                    if (tmpArg.equals("0") || tmpArg.equals("false"))         // "false" in ooRexx
                    {
                        tmpArg="false";     // a Boolean representing false
if (bDebug) System.err.println("\t\t\t>>>  tmpArg=\"false\"!");
                    }

                    // else if (tmpArg.equals("1") || tmpArg.equalsIgnoreCase(".TRUE") || tmpArg.equalsIgnoreCase("TRUE"))
                    else if (tmpArg.equals("1") || tmpArg.equals("true"))    // "true" in Rexx
                    {
                        tmpArg="true";      // a Boolean representing true
if (bDebug) System.err.println("\t\t\t>>>  tmpArg=\"true\"!");
                    }
                    else                    // cannot be considered to be a Boolean
                    {
if (bDebug)
System.err.println("\t\t\t>>>  Not a Boolean --> BREAK!");
                        break;
                    }
                }

                // BSF uses str.charAt(0), accepting any string, which is far too unrestricted !
                // a char/Character is only acceptable if the (Rexx) string consists of exactly one char
                if (paramTypes[k]==char.class || paramTypes[k]==java.lang.Character.class)   // ---rgf, 2005-07-07: make sure a Character is converted correctly
                {
if (bDebug) System.err.println("\t  >>> >>>  checking for {char|Character} value!");
                    // ---rgf, 2006-05-29: be stricter than Java, only accept "0", "1", "false", "true", ".false" and ".true" as Character's

                    if (tmpArg.length()!=1)     // a char or Character must be exactly of size 1 !
                    {
if (bDebug) System.err.println("\t\t\t>>>  Not a Character --> BREAK!");
                        break;
                    }
                }

                    // 2003-09-10, make sure to intercept exceptions while converting
                    // Object o= cvtor.convert( String.class, paramTypes[k], funcArgs[k]);
                Object o=null;
                try
                {
                    // o=cvtor.convert( String.class, paramTypes[k], funcArgs[k]);
                    o=cvtor.convert( String.class, paramTypes[k], tmpArg);
if (bDebug) System.err.println("\t           coercion succssful, o=\""+o+"\", type: \""+o.getClass()+"\". <--- <--- <---");

                }
                catch (Exception e)
                {
if (bDebug) System.err.println("\t            cvt.convert() UNSUCCSSFUL, k=\""+k+"\", paramTypes[k]=\""+paramTypes[k]+"\", tmpArg=\""+tmpArg+"\".getClass()=\""+tmpArg.getClass()+"\" .getClass().toString()=\""+tmpArg.getClass().toString()+"\", Exception: "+e);

                   o=null;
                }


                if (o==null) // co-ercion failed: this is the wrong method, hence break!
                {
if (bDebug) System.err.println("\t           ) ---> k="+k+": coercion yielded 'null', breaking!!");
                   break;
                }
                coercedArgs[k]=o; // save coerced object instead
            }
        }

if (bDebug) System.err.println("\tcoerceArgs() ---> k="+k+" nrArgs="+nrArgs);

        if (k==nrArgs)    // no break, hence all arguments co-erced successfully!
        {
if (bDebug) System.err.println("\tcoerceArgs(): SUCCESSFUL! :-)");
            return coercedArgs;

        }

if (bDebug)
System.err.println("\tcoerceArgs(): UNsuccessful :-( ---> returning 'null'!");
        return null;        // coercion was *not* successful, hence return nothing
    }

    /** Allow lookup of BSFRegistry entries.
     *
     * @param beanName string denoting the index into the BSFRegistry
     * @return the Java object matching <code>beanName</code>, if not found <code>null</code>
     *
     * @since 2012-02-19
     */
    // RexxEngine needs this static
    static protected Object lookupBean(RexxAndJava rajo, String beanName)
    {
        final boolean bDebug= // true;
                              false;


// if (bDebug) System.err.println(rajo+".lookupBean():     beanName=["+beanName+"]");
if (bDebug) System.err.println(rajo+".lookupBean():     beanName=\""+beanName+"\"");

        RAJBean bean=null;
        String  trueBeanName=beanName;
        //rgf20220720 synchronized (lockRajRegistry)
        {
            bean=rajRegistry.get(beanName);

if (bDebug && bean==null)
{
// System.err.println("//*...*// attempt #1: lookupBean(beanName=["+beanName+"]): NOT FOUND! \\\\...\\\\");
System.err.println("//*...*// attempt #1: lookupBean(beanName=\""+beanName+"\"): NOT FOUND! \\\\...\\\\");
}
                // bean not found, maybe still has prefix ?
            if (bean==null && rajo.bsfPrefixReturnValue && beanName.startsWith(OBJECT_INDICATOR_PREFIX))
            {
                trueBeanName=beanName.substring(3);  // remove prefix from bean
                bean=rajRegistry.get(trueBeanName);         // try to get now

if (bDebug && bean==null)
{
//    System.err.println("//*...*// attempt #2: lookupBean(beanName=["+beanName+"],boolean): bean=["+bean+"] \\\\...\\\\");
    System.err.println("//*...*// attempt #2: lookupBean(beanName=\""+beanName+"\",boolean): bean=\\"+bean+"/ \\\\...\\\\");
}
            }
        }


if (bDebug==true)
{
//    System.err.println("RAJ: lookupBean(\""+beanName+"\"): bean=["+bean+"], bean.javaObject.getClass()=["+
    System.err.println("RAJ: lookupBean(\""+beanName+"\"): bean=\""+bean+"\", bean.javaObject.getClass()=\""+
                       (bean==null ? null :
                                    (bean.javaObject==null ? null : bean.javaObject.getClass())
                       )
//                       +"]");
                       +"\"");
}

        // not found, maybe a declared bean (maintained by BSFEngine, declared usually via BSFMansger)?
        if (bean==null)
        {
            RexxEngine re=(RexxEngine) rajo.rexxEngine;
            if (re.hasDeclaredBeans && re.engineDeclaredBeans.containsKey(trueBeanName))
            {
                return ((BSFDeclaredBean)re.engineDeclaredBeans.get(trueBeanName)).bean;

            }
        }

        return (bean==null ? null : bean.javaObject);
    }



    /** Allow JNI to easily lookup the BSFRegistry.
     *
     * @param beanName string denoting the index into the BSFRegistry
     * @return the Java object matching <code>beanName</code>, if not found <code>null</code>
     */
    private Object lookupBean4JNI(String beanName)
    {
        final boolean bDebug=false;

if (bDebug) System.err.println(this+".lookupBean4JNI(): beanName=["+beanName+"], bTerminated=["+bTerminated+"]");

        if (bTerminated==true)
        {
            // return null;
            return (bsfPrefixReturnValue ? OBJECT_INDICATOR_PREFIX : "")+null4Rexx;                     // return the Rexx-String representing "null"
        }

        return lookupBean(this, beanName);
    }



    /** Allow JNI to easily register a bean.
     *
     * @param object a Java object which should be registered
     * @return beanName used to store and needed for retrieving the object in/from the BSFRegistry
     */
    private String registerBean4JNI(Object object)
    {
// rgf, 201507
if (bDebugRefCounter==true)
System.err.println(this+":  registerBean4JNI(object=["+object+"]): object.getClass()->["+(object==null? null : object.getClass())+"]");

        if (bTerminated==true)
        {
            return (bsfPrefixReturnValue ? OBJECT_INDICATOR_PREFIX : "")+null4Rexx;                     // return the Rexx-String representing "null"
        }
// rgf, 201507
if (bDebugRefCounter==true)
System.err.println(this+":  registerBean4JNI(object=["+object+"]): object.getClass()->["+(object==null? null : object.getClass())+"]");

        return registerBean(this, makeBeanName(this, object), object);
    }



    /** This method registers an <em>object</em> with the given <em>beanName</em> with
     *  the BSF registry, if not registered yet. In addition a reference counting is
     *  carried out.
     *
      *  @param beanName name of the object to be registered
      *
      *  @param object to be registered
      *
      *  @return returns the beanName
      */
    // RexxEngine needs this to be static
    static protected String registerBean(RexxAndJava rajo, String beanName, Object object)
    {

        if (rajo.bTerminated==true)
        {
            return (rajo.bsfPrefixReturnValue ? OBJECT_INDICATOR_PREFIX : "")+null4Rexx;                     // return the Rexx-String representing "null"
        }

final boolean bDebug=false;
if (bDebug)
{
    System.err.print(rajo+".registerBean(): rajo.bsfPrefixReturnValue=["+rajo.bsfPrefixReturnValue+"] <=== <--- <===");
    System.err.print(rajo+".registerBean(beanName=["+beanName+"], object=["+object+"]: ");
}

        //rgf20220720 synchronized (lockRajRegistry)
        {
            RAJBean bean = rajRegistry.get( beanName );  // already registered?
            if (bean==null)                  // we need to create the bean
            {
                bean=new RAJBean(beanName, object);
                rajRegistry.put(beanName, bean);
if (bDebug) System.err.print("did not exist, CREATED!");
            }
            else    // exists already, increase refCounter
            {
                bean.refCount+=1;
if (bDebug) System.err.print("existed alread, refCount increased");
            }

if (bDebug) System.err.println(" -> bean.refCount=["+bean.refCount+"]");


if (bDebugRefCounter)
{

    if (object instanceof String)
    {
        String str=(String) object;
        int len=str.length();
        System.err.println("/-->/-->/storing a STRING /-->/["+str.substring(0, (len<51 ? len-1 : 50) ) +"] \\<--\\<--\\");
    }
    if (bean.refCount>bDebugRefCounterThreshold || rajRegistryToWatch.get(beanName)!=null)
    {
        System.err.println("//++// registerBean, RAJBean: "+bean+" \\\\++\\\\ (AFTER increasing refCount=["+bean.refCount+"])");
        if (rajRegistryToWatch.get(beanName)==null)
        {
            rajRegistryToWatch.put(beanName, bean);
        }
    }
}

        }

        return (rajo.bsfPrefixReturnValue ? OBJECT_INDICATOR_PREFIX : "")+beanName;   // if so, return beanName

    }



    /** This method replaces an already registered Java <em>object</em> with the one supplied as the argument.
     *
      *  @param beanName name of the object to be replaced
      *  @param object that replaces the current
      *
      *  @return returns the beanName
     * @since 2016-12-19
      */
    protected String rawRegisterBean(String beanName, Object object)
    {
final boolean bDebug=false; // true;
if (bDebug)
{
    System.err.println("RAJ.-RAW-rawRegisterBean(beanName=["+beanName+"], object=["+object+"]: ");
}
        RAJBean bean = null;
        //rgf20220720 synchronized (lockRajRegistry)
        {
            bean=rajRegistry.get( beanName );  // already registered?
            if (bean==null)                  // we need to create the bean
            {
                bean=new RAJBean(beanName, object);
                rajRegistry.put(beanName, bean);
            }
            else    // exists already, replace Java object in bean with the supplied one, increase refCounter
            {
                bean.javaObject=object;
                bean.refCount+=1;
            }
        }


if (bDebugRefCounter) // && bean.refCount>3)
{
    System.err.println("//++// rawRegisterBean, RAJBean: "+bean+" \\\\++\\\\ (AFTER increasing refCount)");
}

        return (bsfPrefixReturnValue ? OBJECT_INDICATOR_PREFIX : "")+beanName;   // if so, return beanName
    }



    /** This method allows for fetching the current reference count for the supplied bean.
      *
      *  @param beanName name of the Bean for which the current reference count should be returned
      *
      *  @return returns number of reference counts left (&quot;-1&quot not in registry,
     *           &quot;0&quot& removed from registry)
      */
    private static int getBeanRefCount(String beanName )
    {
        final boolean bDebug= // true;
                              false;

if (bDebug==true) System.err.println("RAJ:   ===> RexxAndJava.getBeanRefCount("+beanName+") ...");

        RAJBean bean = null;

        //rgf20220720 synchronized (lockRajRegistry)
        {
            bean = rajRegistry.get( beanName );
            if (bean==null)     // not in registry
            {
                return -1;
            }
        }
        return bean.refCount;
    }


    /** This method allows for unregistering Beans, taking into account reference counters.
      * Only if the reference counter is 0, will the given Bean be unregistered.
      *
      *  @param beanName name of the Bean to be unregistered
      *
      *  @return returns number of reference counts left (&quot;-1&quot not in registry,
     *           &quot;0&quot& removed from registry)
      */
    // protected boolean unregisterBean(String beanName )
    protected int unregisterBean(String beanName )
    {

        final boolean bDebug= // true;
                              false;

if (bDebug==true || bDebugRefCounter==true)
System.err.println("RAJ:   ===> RexxAndJava.unregisterBean("+beanName+"): bTerminated=["+bTerminated+"] ...");


/* // rgf, 2016-11-30: even if the Rexx engine is terminated, unregisterBean remains valid, reducing the refCount
   // of the registered Java object
        if (bTerminated==true)
        {
            return false;
        }
*/

// FIXME: remove output after debugging
if (bDebug==true && bTerminated==true)
{
    System.err.println("RAJ:   ===> RexxAndJava.unregisterBean(): ***************** ***************** bTerminated=true !!!! beanName=["+beanName+"] ***************** *****************");
}


if (bDebug) // testing; TODO: remove
{
    System.err.println("RAJ:   ===> RexxAndJava.unregisterBean(beanName="+beanName+")");
}
            RAJBean bean = null;

            //rgf20220720 synchronized (lockRajRegistry)
            {
                bean = rajRegistry.get( beanName );
// if (bDebugRefCounter && (bean.refCount>3 || rajRegistryToWatch.get(beanName)!=null))
if (bDebugRefCounter && rajRegistryToWatch.get(beanName)!=null)
System.err.println("RAJ:   ===> RexxAndJava.unregisterBean("+beanName+"), bean.refCount=["+bean.refCount+"]  ...");

                // bean not found, maybe still has prefix ?
                if (bean==null && bsfPrefixReturnValue && beanName.startsWith(OBJECT_INDICATOR_PREFIX))
                {
                    beanName=beanName.substring(3);  // remove prefix from bean
                    bean=rajRegistry.get(beanName);
                }

                if (bean==null)
                {
if (bDebugRefCounter)
System.err.println("RAJ:   ===> RexxAndJava.unregisterBean("+beanName+"), not in registry anymore!");

                    // return false;
                    return -1;      // indicate not in registry
                }

if (bDebugRefCounter)
{
    // if (bean.refCount>3 || rajRegistryToWatch.get(beanName)!=null)
    if (rajRegistryToWatch.get(beanName)!=null)
    {
    System.err.println("//--// RAJ.unregisterBean(), decreasing refCount! bean=["+bean+"], new refCount=["+(bean.refCount-1)+"] \\\\--\\\\");
    }
}
                bean.refCount-=1;       // reduce counter
                if (bean.refCount==0)   // dropped to 0, remove bean
                {

if (bDebugRefCounter)
{
    if (rajRegistryToWatch.get(beanName)!=null)
    {
        String str=" ";

        if (bean.javaObject instanceof RexxProxy)
        {
            try {
                str="["+((RexxProxy) bean.javaObject).sendMessage0("STRING")+"] ";
            }
            catch (Exception exc)
            {}
        }
        System.err.println("//--// RAJ.unregisterBean(), REMOVING FROM REGISTRY! beanName=["+beanName+"], bean.refCount=["+bean.refCount+"] "+str+"\\\\--\\\\");
        rajRegistryToWatch.remove(beanName);
    }
    else    // TODO: 20161220, rgf: temporarily show all removals!
    {
        System.err.println("//--// RAJ.unregisterBean(), REMOVING FROM REGISTRY! beanName=["+beanName+"], bean.refCount=["+bean.refCount+"] \\\\--\\\\");
    }
}

                    rajRegistry.remove(beanName);
if (bDebugRefCounter)
System.err.println("RAJ:   ===> RexxAndJava.unregisterBean("+beanName+"), now REMOVED from registry!");
                }
            }

            // return true;
            return bean.refCount;       // return current reference counts
    }




    /** This method allows for unregistering Beans from native code.
     *  Its code is a copy of {@link unregisterBean(String beanName ).}
      *
      *  @param beanName name of the Bean to be unregistered
      *
      *  @return returns number of reference counts left (&quot;-1&quot not in registry,
     *           &quot;0&quot& removed from registry)
      */
    private static int unregisterBean4JNI(String beanName )
    {
        final boolean bDebug= // true;
                              false;

if (bDebug==true || bDebugRefCounter==true)
System.err.println("RAJ:   ===> RexxAndJava.unregisterBean4JNI("+beanName+") ...");

        RAJBean bean = null;

        //rgf20220720 synchronized (lockRajRegistry)
        {
            bean = rajRegistry.get( beanName );
// if (bDebugRefCounter && (bean.refCount>3 || rajRegistryToWatch.get(beanName)!=null))
if (bDebugRefCounter && rajRegistryToWatch.get(beanName)!=null)
System.err.println("RAJ:   ===> RexxAndJava.unregisterBean4JNI("+beanName+"), bean.refCount=["+bean.refCount+"]  ...");

            if (bean==null)
            {
if (bDebugRefCounter) System.err.println("RAJ:   ===> RexxAndJava.unregisterBean4JNI("+beanName+"), not in registry anymore!");

                return -1;
            }

if (bDebugRefCounter)
{
    // if (bean.refCount>3 || rajRegistryToWatch.get(beanName)!=null)
    if (rajRegistryToWatch.get(beanName)!=null)
    {
        System.err.println("//--// RAJ.unregisterBean(), decreasing refCount! bean=["+bean+"], new refCount=["+(bean.refCount-1)+"] \\\\--\\\\");
    }
}
            bean.refCount-=1;       // reduce counter
            if (bean.refCount==0)   // dropped to 0, remove bean
            {

if (bDebugRefCounter)
{
    if (rajRegistryToWatch.get(beanName)!=null)
    {
        String str=" ";

        if (bean.javaObject instanceof RexxProxy)
        {
            try {
                str="["+((RexxProxy) bean.javaObject).sendMessage0("STRING")+"] ";
            }
            catch (Exception exc)
            {}
        }
        System.err.println("//--// RAJ.unregisterBean(), REMOVING FROM REGISTRY! beanName=["+beanName+"], bean.refCount=["+bean.refCount+"] "+str+"\\\\--\\\\");
        rajRegistryToWatch.remove(beanName);
    }
    else    // TODO: 20161220, rgf: temporaryly show all removals!
    {
        System.err.println("//--// RAJ.unregisterBean(), REMOVING FROM REGISTRY! beanName=["+beanName+"], bean.refCount=["+bean.refCount+"] \\\\--\\\\");
    }
}

                rajRegistry.remove(beanName);
            }
        }
        return bean.refCount;
    }



    /** This method determines what String content to return; if a non-primitive Java object
     *  a unique beanName is created and used to save the Java object in the BSFRegistry,
     *  returning the beanName.
      *
      *  @param o the object which should get returned as a string to Rexx.
      *
      *  @return  a String rendering of the primitive types and String.
      *           Otherwise create a unique bean name, register the object
      *           under it and return the bean name. If <code>null</code>,
      *           then the string of {@link #null4Rexx} is returned to Rexx.
      */
     // RexxEngine needs this static
    static protected String makeString4Rexx(RexxAndJava rajo, Object o)  // changed 2003-01-06 from "makeResultString()" to "makeString4Rexx()"
    {
        final boolean bDebug=  // true;     // if true, show debug infos
                               false;

if (bDebug)
{
    System.err.println("makeString4Rexx() 1a: o=["+o+"]:");
    System.err.println("makeString4Rexx() 1b: o.getClass()=\""+(o==null?null:o.getClass())+"\", o=["+(o==null ? null : o.toString())+"]...");
}

       if (o==null)
       {
          return (rajo.bsfPrefixReturnValue ? OBJECT_INDICATOR_PREFIX : "")+null4Rexx;                     // return the Rexx-String representing "null"
       }

       Class cl = o.getClass();

if (bDebug)
{
    if (cl==Character.class) {System.err.println("makeString4Rexx(): charValue="+((Character) o).charValue());}
}

       if (cl==String.class)
       {

if (bDebug) System.err.println("makeString4Rexx(): TSK # 1");
          return (rajo.bsfPrefixReturnValue ? STRING_INDICATOR_PREFIX : "")+((String) o);
       }

       else if (cl==Boolean.class )
       {
          return (rajo.bsfPrefixReturnValue ? STRING_INDICATOR_PREFIX : "")+( ((Boolean) o).booleanValue() ? "1" : "0");
       }

       else if (    cl.isPrimitive() ||
                cl==Integer.class    || cl==Character.class  ||
                cl==Long.class       ||
                cl==Float.class      || cl==Double.class     ||
                cl==Byte.class       || cl==Short.class
               )
       {
          return (rajo.bsfPrefixReturnValue ? STRING_INDICATOR_PREFIX : "")+o.toString();  // o.k.
       }

         // are we returning a netrexx.lang.Rexx instance, if so, use its String value
        if (nlR_class!=null && cl==nlR_class) {
            return (rajo.bsfPrefixReturnValue ? STRING_INDICATOR_PREFIX : "")+o.toString();
        }

                // an Object, register it as a bean, so it becomes
                // possible to refer to from Rexx as well

       String beanName = makeBeanName(rajo, o);

if (bDebug) System.err.println("makeString4Rexx(): returning -> registerBean(rajo, beanName, o), beanName=["+beanName+"]");

       return registerBean(rajo, beanName, o);
    }



    // rgf, 2018-01-05: consequence of making utility methods static
    /** This method will be fetched and excercised from native code.
     */
    private String makeString4Rexx(Object o)
    {
        return makeString4Rexx(this,o);
    }



    /** This method creates an identifer (unique) string value for the passed in object.
      *
      *  @param o the object for which a unique string value should be created
      *
      *  @return  <code>null</code>, if the argument was <code>null</code>,
     *            else a String, identifying (uniquely) the object for use with the BSF registry
      */
    // RexxEngine needs makeString4Rexx() to be static which invokes this method, hence it needs to be static too
    static public String makeBeanName(RexxAndJava rajo, Object o)
    {
        final boolean bDebug= // true;   // if true, show debug infos
                              false;

        if (o==null)
        {
            return null;
        }

            // rgf, 2009-07-13: all method objects of the same name have the same hashCode() (does
            //                  not apply to constructor objects only!), hence need for using
            //                  System.identityHashCode() instead
        String beanName="" + o.getClass().getName() + '@' + Integer.toHexString( System.identityHashCode(o) );

            // rgf, 2012-11-01: handle case where System.identityHashCode() returns duplicates
        Object olb=null;
        olb=lookupBean(rajo, beanName);

        if (olb!=null && o!=olb)   // oops, we got a duplicate identityHashCode for the same class!
        {   // make it into an identifier (unique) string
            //rgf20220720 synchronized (lockRajRegistry)  // shelter increasing and use of spilloverCounter
            {
                beanName=beanName+"_spilloverCounter_"+Integer.toHexString(++spilloverCounter);
            }
// if (bDebug)  System.err.println("makeBeanName(): duplicate identityHashCode, spilloverCounter used, now beanName=["+beanName+"]");
if (bDebug)  System.err.println("makeBeanName(): duplicate identityHashCode, spilloverCounter used, now beanName=\""+beanName+"\"");
        }
// System.err.println("RexxAndJava.makeBeanName(rajo,o): o=["+o+"] -> beanName=["+beanName+"] | o.getClass()=["+o.getClass()+"], o.getClass().toString()=["+o.getClass().toString()+"]");
if (bDebug)  System.err.println("RexxAndJava.makeBeanName(rajo,o): o=\""+o+"\" -> beanName=\""+beanName+"\" | o.getClass()=\""+o.getClass()+"\", o.getClass().toString()=\""+o.getClass().toString()+"\"");

        return beanName;
    }


    /** Called by {@link RexxEngine#terminate()}, Will free the references to {@link BSFManager} and {@link RexxEngine}.
     *
     *  {@link #isTerminated()} to test whether the Rexx interpreter instance of
     *  this {@link RexxEngine} got terminated.
     *
     * To halt all Rexx threads of this engine's Rexx interpreter instance peer use
     * {@link #jniRexxHaltInterpreterInstance (String rii_ID)}.
     *
     * @since 2013-06-25
    */
    synchronized protected void terminate()
    {
        final boolean bDebug = // true;
                               false;

        if (bDebug)
        {
            String strRe_id="";
            if (rexxEngine!=null)
            {
                strRe_id=" [RE_"+((RexxEngine) rexxEngine).id+"]";
            }
            System.err.println("*** TERMINATE *** bTerminated=["+bTerminated+"] *** rii_ID=["+rii_ID+"]"+strRe_id+" rexxEngine=["+rexxEngine+"] *** TERMINATE *** *** TERMINATE *** *** TERMINATE *** *** TERMINATE *** *** TERMINATE *** *** TERMINATE ***");
        }

        bTerminated=true;       // from now on do not use BSFManager and RexxEngine related methods
        rexxEngine =null;       // nullify, release reference
        mgr        =null;       // nullify, release reference
    }

    /** Getter method for field <code>bTerminated</code>.
     *
     * @return <code>true</code>, if Rexx engine got successfully terminated, <code>false</else>
     *
     * @since 2013-06-25
     */
    public boolean isTerminated()
    {
        return bTerminated;
    }



   /** Class to exit the JVM, will be executed concurrently, sleeps and then
     * <code>calls System.exit(exit_number)</code>. This allows the Rexx side
       to gain time to shutdown properly.
     */
   class ExitDelayed implements Runnable
   {
         /** Holds the return value to be returned.             */
         int exitCode=0;

         /** Holds the time in milliseconds to wait before terminating the virtual machine.
             This should allow Rexx time to shutdown properly.  */
         long sleepTime=100l;

         /** Saves the <code>exitCode</code>. */
         ExitDelayed (int exitCode, long sleepTime)
         {
            this.exitCode  = exitCode;  // save exitCode
            this.sleepTime = sleepTime; // save time to sleep before terminating the JVM
         }

         /** This makes this thread runnable. Will wait {@link #sleepTime} and
           * terminates the Java virtual machine with {@link #exitCode}.
           */
         public void run() // throws InterruptedException
         {
            Thread thisThread = Thread.currentThread(); // get current Thread
            try
            {
               mgr.terminate();         // let the BSF manager "terminate gracefully"
               thisThread.sleep( sleepTime );   // sleep the indicated time
            }
            catch (InterruptedException e)
            {
               e.printStackTrace();
            }
            finally                     // in any case, kill the JVM!
            {
              System.exit(exitCode);    // now kill JVM
            }
         }
   }




    /** Inner class to implement a Synchronized ReaderWriter, where a
      * read on an empty Vector blocks the read, until a write occurs (with optional timeout).
      */
    protected class SyncPutGet
    {
        /** Vector to store the text sent by the eventListeners. */
        private Vector<Object> eventTextVector     = new Vector<Object>();      // normal priority
        private Vector<Object> eventTextVectorLow  = new Vector<Object>();      // low ("batch") priority
        private Vector<Object> eventTextVectorHigh = new Vector<Object>();      // high ("alarm") priority


        /** Get an object from the vector. If empty, block for the
          * given time.
          *
          * @param millis time to wait in milliseconds, if 0 waits until an object becomes available.
          *
          * @return the first object from the vector or <code>null</code>, if
          *         empty.
          */
        synchronized Object get (long millis) throws java.lang.InterruptedException
        {
            if ( eventTextVector    .isEmpty() &&
                 eventTextVectorLow .isEmpty() &&
                 eventTextVectorHigh.isEmpty()    )     // empty, block until filled
            {
               wait(millis);
            }

            if (eventTextVector    .isEmpty() &&
                eventTextVectorLow .isEmpty() &&
                eventTextVectorHigh.isEmpty()    )     // empty, return null
            {
// System.err.println("RexxAndJava.SyncPutGet.get(), about to return, nothing in any queue.");
                return null;    // awakened due to time-out?
            }

            Object o;
                // return the eventText in the order: High-Normal-Batch
            if ( ! eventTextVectorHigh.isEmpty())       // Highest priority!
            {
                // for supporting JRE 1.1.8, ---rgf, 2001-05-26
               o=eventTextVectorHigh.firstElement();
                 eventTextVectorHigh.removeElementAt(0);
            }

            else if ( ! eventTextVector.isEmpty() )     // Normal priority
            {
                // for supporting JRE 1.1.8, ---rgf, 2001-05-26
               o=eventTextVector.firstElement();
                 eventTextVector.removeElementAt(0);
            }

            else   // default: now lowest priority's turn
            {
                // for supporting JRE 1.1.8, ---rgf, 2001-05-26
               o=eventTextVectorLow.firstElement();
                 eventTextVectorLow.removeElementAt(0);
            }

            return o;
        }

        /** Adds an object to the vector and makes sure that waiting threads
          * are notified.
          *
          * @param o object to add to the vector.
          *
          * @param priority an integer value indicating the priority of the posted
          *        event, one of:

          *        <p><ul>
                   <li>&quot;<code>2</code>&quot;: high ('alarm level') priority.
                   <li>&quot;<code>1</code>&quot;: normal (<strong>default</strong>) priority, and
                   <li>&quot;<code>0</code>&quot;: low ('batch level') priority,
                   </ul>
          *
          */
        synchronized void put (Object o, int priority)
        {
            switch (priority)
            {
               case  2:         // add the element to the high priority vector
                           eventTextVectorHigh.addElement(o);   // changed to addElement() for JRE 1.1.8, ---rgf
                  break;

               case  0:         // add the element to the low priority vector
                           eventTextVectorLow.addElement(o);    // changed to addElement() for JRE 1.1.8, ---rgf
                  break;

               case  1:         // add the element to the normal priority vector
               default:
                           eventTextVector.addElement(o);       // changed to addElement() for JRE 1.1.8, ---rgf
                  break;
            }

            notifyAll();        // now notify all
        }
    }

    /** 'Pretty print': returns string value of supplied object enclosed in square brackets. */
    String pp(Object o)
    {
        if (o==null) return "<null>";
        return "["+o+"]";
    }

    // 2009-05-01
    /** Truncates string, if longer than given maxLength and append ellipsis (three dots: '...'). */
    String truncString (String s, int maxLength)
    {
        if (s==null)
        {
            return null;
        }

        if (s.length()>maxLength)
        {
            return s.substring(0, maxLength-1)+"...";
        }

        return s;
    }


    /** Makes sure that supplied object's String value gets truncated, if longer than given maxLength and append ellipsis (three dots: '...').
     *
     * @param o the Object which String value may have to be truncated if exceeding maxLength
     * @param maxLength the maximum length of the supplied String before truncating it
     *
     * @return returns the String value of the supplied object truncated and with an ellipsis, if longer than maxLength
    */
    String truncObject (Object o, int maxLength)
    {
        if (o==null)
        {
            return null;
        }
        String s = (o instanceof String ? (String) o : o.toString());

        if (s.length()>maxLength)
        {
            return s.substring(0, maxLength-1)+"...";
        }
        return s;
    }


    static private String getCauseAsString (String title, Exception e)
    {
        final boolean bDebug= // true;    // if true, show debug infos
                              false;

        Throwable c=null;

        if (c instanceof InvocationTargetException) // rgf, 2010-03-27
        {
            c=((InvocationTargetException)e).getTargetException();   // unwrap and show exception the invoked method has thrown

if (bDebug) System.err.println("***debug RexxAndJava.getCauseAsString(): InvocationTargetException=["+e+"]\n"+
                   "\t--> getTargetException()=["+c+"]\n"+
                   "\t--> getCause()          =["+e.getCause()+"]");
        }

        if (c==null)
        {
            c=e.getCause();
        }

        if (c==null)
        {
            return "";
        }
        return title+"["+c.toString()+"]";
    }


    static private void RgfMsgBox (String message, char kind) {

        final JFrame frame = new JFrame("RexxAndJava - RgfMsgBox");

        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

        frame.addWindowListener(
            new WindowAdapter()
            {
                public void windowClosing(WindowEvent e) {
                    // System.exit(0);     // kill JVM ???
                    frame.dispose();
                    return;
                }
            }
        );

        if (kind=='1')  // information
        {
            JOptionPane.showMessageDialog(frame, message,"information", JOptionPane.INFORMATION_MESSAGE);
        }
        else
        {
            JOptionPane.showMessageDialog(frame, message,"error"      , JOptionPane.ERROR_MESSAGE      );
        }

        frame.dispose();
    }




    /** Creates a new Rexx interpreter instance using the ooRexx 4.0 API <code>RexxCreateInterpreter()</code>.
     *  This method honors optional Rexx interpreter instance settings, such that a default
     *        command environment can be defined, as well as Rexx command handlers
     *        (and eventually Rexx exit handlers) implemented in Java.
     *
     * @return a String representing the created Rexx interpreter instance ID or <code>null</code>, if
     *         no Rexx interpreter instance could be created
     *
     * @since 2012-02-04
    */
    protected String createRexxInterpreterInstance(RexxConfiguration rc) throws BSFException
    {
final boolean bDebug= // true;
                      false;

        if (rii_ID!=null)   // already created for this RAJO!
        {
            throw new BSFException("A Rexx interpreter instance has been created already having the ID ["+rii_ID+"]");
        }

        // --rgf, 2014-04-02: now initialization takes place in constructor, such that calling jniProcEnvironment() can be carried out without a physical Rexx interpreter instance
        // jniSetupNativeJVMPointer();         // make sure C++ side gets a JVM pointer

        Object options[]=null;
        if (rc!=null)
        {
            rc.modifiable=false;            // from now on do not allow any changes to the structure of options
            options=rc.getArguments4JNI();  // get arguments for native code to configure the Rexx instance
        }

        String tmp_rii_ID=jniRexxCreateInterpreterInstance(options);  // create interpreter instance
        set_rii_ID(tmp_rii_ID);             // set the returned rii_ID

        // 2025-08-27, fetch the Rexx interpreter's identifier value
        String code="return .context~interpreter";
        String fileName="RexxAndJava.java_createRexxInterpreterInstance";

        Object res=jniRexxRunProgram(
                tmp_rii_ID, // newly created RexxInstance instance ID
                2,          // invocationType,         // 1=CallProgram, 2=CallProgramFromData, 3=LoadPackage, 4=LoadPackageFromData
                fileName,   // String  fileName,               // filename which contains the program to run
                code,       // String  programData,            // Rexx code to execute; if given "fileName" denotes a (symbolic) name for this code
                null        // Object[]args                    // arguments
                );

if (bDebug)
{
    System.err.println("1 - "+fileName+": rexxEngine.id=["+rexxEngine.id+"], rexxEngine="+rexxEngine);
    System.err.println("2 - "+fileName+": res=["+res+"] res.getClass()="+res.getClass()+" .toString()="+res.getClass().toString());
}
        long rexxId = 0;
        try
        {
            rexxId=Long.parseLong(res.toString());
            rexxEngine.setId(rexxId);
        }
        catch (NumberFormatException nfe)
        {
            System.err.println(":( :( :( ---> "+fileName+": Long.parseLong("+res+") caused: "+nfe);
        }
if (bDebug)
{
    System.err.println("3 - "+fileName+": rexxEngine.id=["+rexxEngine.id+"], rexxEngine="+rexxEngine);
    System.err.println(this+".createRexxInterpreterInstance(...), returning rii_ID=["+tmp_rii_ID+"] for Rexx instance identifier [R"+rexxId+"]");
}

        return tmp_rii_ID;
    }



//
    /** This class maintains the name, the Java object denoted by it and the reference count of the Java object.
     *  The name will be used as the key.
     *
     * @since 2016-11-27
      */
    public static class RAJBean    // "RexxAndJava"-Bean
    {
            // package private
        /** The name used to store the bean in the registry. */
        String name=null;

        /** The Java object (&quot;Java bean&quot;).
         */
        Object javaObject=null; // the Java object

        /** Serves as the reference count field for maintenance purposes of the {@link #rajRegistry}.
         */
        int refCount=1;         // allows to maintain the reference count value for this particular bean

        /* No default constructor for this class. */
        private RAJBean()
        {}

        /** Constructor.
         *
         * @param name the name used for the Java object
         * @param javaObject the Java object
         */
        public RAJBean(String name, Object javaObject)
        {
            this.javaObject=javaObject;
            this.name=name;
        }

        public Object getName()
        {
            return name;
        }
        public Object getJavaObject()
        {
            return javaObject;
        }
        public int getRefCount()
        {
            return refCount;
        }
        public String toString()
        {
            return "RAJBean@"+Integer.toHexString( System.identityHashCode(this) )+"[name="+name+",javaObject="+javaObject+",refCount="+refCount+"]";
        }

/*
public void finalize()
{
    System.err.println("RAJBean.finalize(): name=["+name+"], refCount=["+refCount+"], javaObject=["+javaObject+"]");
}
*/

    }

}
/*
javah -jni  org.rexxla.bsf.engines.rexx.RexxAndJava
javap -s -p org.rexxla.bsf.engines.rexx.RexxAndJava
*/
