/* OdmJniBind.java 0.21              UTF-8                  dh:2007-11-10
 *
 * The OdmJniBind class is a class of static-only methods that provide
 * dynamic connection between a Java-based ODMA-aware application and the
 * ODMJNI 1.0 classes that implement info.odma.practical100 interfaces
 * using the ODMA Connection Manager and ODMA API.
 *
 * There are four static public methods and one constant:
 *
 *      MAX_APPID_SIZE identifies the maximum number of Basic Latin 1
 *      Unicode character encodings that are permitted in an Application ID.
 *
 *      wfAppId(appId) returns a bool to confirm whether the appId string
 *      is well-formed and acceptable as an application identifier.  These
 *      first two are provided by the practical100.OdmNullBind implementa-
 *      tion.
 *
 *      getVersion() returns a string form of the JNI version being used
 *      by the JVM on which OdmJniBind.getVersion() is being run.
 *
 *      OdmJniBind.application(appID) accepts the ODMA Application ID of
 *      the application and returns the info.odma.practical100.OdmConnection
 *      interface to be used for further operations.
 *
 *      OdmJniBind.application(appID, appWindow) also accepts a non-null
 *      java.awt.Window the is to be used for modal dialog functions of the
 *      DMS integration.
 *
 * Typical start-up is via a statement such as
 *
 *      odmConnection myConnection = OdmJniBind.application("MyAppId");
 *
 * All other methods of this class are reserved for private coordination
 * among the odmjni100 implementation classes.
 */

package info.odma.odmjni100;

public class OdmJniBind extends info.odma.practical100.OdmNullBind
{
    /* This is a class of exclusively-static methods used to coordinate
     * the instantiation of other odmjni100 package classes and to
     * implement access to the OdmNative100 apparatus via static native
     * methods.
     *
     * All odmjni100 native methods are implemented on this class.  That
     * way the odmjni100.dll is tied to this single class and is fully-
     * loaded with the loading of this class (or close enough to that).
     */


    /* Methods from OdmNullBind
     * ************************ */

            /* MAX_APPID_SIZE and wfAppId are inherted without change.
               */


    /* New Methods of OdmJniBind
     * ************************* */


    private static native int jniVersion();
        /* The version of JNI in two halves of an int, as
           delivered by JNI Ienv.GetVersion().

           This is used to confirm access to JNI and the odmjni100 DLL.  It
           is a sanity-check function in the startup process.

           This is used by the getVersion() method.
           */



    public static java.lang.String getVersion()
    {   /* Convert the JNI version number to a correctly-formatted String.
           */

        int jVersion = jniVersion();

        int verMajor = jVersion >>> 16;

        int verMinor = jVersion - (verMajor << 16);

        return "" + verMajor + "." + verMinor;

        } /* getVersion */



    static long getInterfaceRef(long interfaceReturn)

    {   /* To avoid callbacks and provide status as well as interfaces,
           the native methods that return references to interfaces
           use their long returns to indicate error conditions as well.

           The returned long value is either an error status or it is
           an interface reference.  It is never both.

           This function examines a returned long value and delivers
           either the interface reference (a nonzero value) or 0.
           Here, 0 means there is no reference and no attempt to use
           the interface should occur.

           Use getInterfaceStatus to extract any possible error status.
           */

        if (interfaceReturn == (interfaceReturn & 0x1F) )
             return 0L;
                /* Because the value is too small to be a reference */
        else return interfaceReturn;
                /* Because the value is not an error status value. */

        } /* getInterfaceRef */



    static int getInterfaceStatus(long interfaceReturn)

    {   /* If the interfaceReturn value is an error status, that
           value is returned.  Otherwise, 0 is returned.

           Note that a NULL (0) interfaceReturn will simply
           be treated as a null reference and a 0 status.
           We don't expect to have any of those.
           */

        if (interfaceReturn == (interfaceReturn & 0x1F) )
             return (int) interfaceReturn;
                /* Because the value is in error-status range */
        else return 0;
                /* Because the value is not in error-status range. */

        } /* getInterfaceStatus */


    static native long holdNativeInterface(long interfaceRef);
        /* When an operation has received an interface reference
           as a parameter, that reference is only valid for use
           for the duration of the method (or constructor).

           This function returns an interfaceRef disguise that
           has been held for the caller.  It is then necessary
           for the caller to free the resulting interfaceRef when
           it is no longer required, and before the object holding
           the reference is released.
           */


    static native void freeNativeInterface(long interfaceRef);
        /* this native function will release the provided interface
           reference.  If the interface reference is NULL (0) no
           action is taken.  Otherwise the reference is released
           and the variable that held it should be set to 0.

           Only the one reference is released.  The implementation
           of the interface is not released until all interface
           references that are being held are individually released.
           */


    private static
        info.odma.practical100.OdmConnection
            appRaiser(long rIface)

    {   /* Given the IodmNative reference result for a connection,
           deliver the appropriate interface implementation for the
           status reflected by rIface.
           */

        if (getInterfaceRef(rIface) == 0)
             return info.odma.practical100.OdmNullBind.application(null);
                /* Because we did not get an Interface. */

        else {  /* Instantiate an OdmJniApp to implement the interface.*/

                info.odma.practical100.OdmConnection
                    OdmApp = new OdmJniApp(rIface);
                    /* Using our package's implementation.  The OdmJniApp
                       constructor must arrange to hold its own copy of
                       rIface, releasing that interface reference when
                       it is no longer needed.
                       */

                freeNativeInterface(rIface);
                    /* We no longer need our own reference and release
                       it now.  If OdmJniApp is holding its own copy,
                       it has reserved that one itself. */

                return OdmApp;
                }

        } /* appRaiser */



    public static
        info.odma.practical100.OdmConnection
            application(java.lang.String appId)

    {   /* Associate the specified Application ID with the application
           and deliver an interface appropriate to the achievement of
           a binding or not. */

        return appRaiser(getIodmNative(appId));
        /* XXX: If appId is ill-formed, getIodmNative must fail.
                */

        } /* application(appId) */


    private static native long getIodmNative(java.lang.String appID);
        /* This native function requests creation of an IodmNative
           object and return of a reference to its  IodmApplication100
           interface.  This reference is disguised as a Java long.
           This interface will be held until a freeIodmNative operation
           is performed with it, at which point the particular reference
           is no longer valid.
           */


    public static
        info.odma.practical100.OdmConnection
            application(java.lang.String appId,
                         java.awt.Window appWindow )
                throws info.odma.practical100.OdmError

    {   /* Associate the specified Application ID with the application
           and deliver an interface appropriate to the achievement of
           a binding or not. */

        if (appWindow == null)
             return info.odma.practical100.OdmNullBind.application
                            (appId, appWindow);
                /* XXX: We let OdmNullBind throw the exception because
                        it is arranged to do it properly.
                        */

        return appRaiser(getIodmWinNative(appId, appWindow));
                /* XXX: counting on GetIodmWinNative to fail to deliver
                        an interface if appId is ill-formed.
                        */

        } /* application(appId) */


    private static native long getIodmWinNative(java.lang.String appId,
                                                 java.awt.Window appWin);
        /* This native function requests creation of an IodmNative
           object and return of a reference to its  IodmApplication100
           interface.  This reference is disguised as a Java long.
           This version will establish the supplied Window instance as
           the one to be treated as the parent of all DMS modal dialogs
           produced directly or indirectly via use of this interface.
           */

    static

        {   /* Static initialization of this class specifies
               how to find jawt.dll and also load our only DLL. */

            System.loadLibrary("odmjni100");

            } /* static initialization */

    } /* OdmJniBind */



/* 0.21 2007-11-10-15:31 Add MAX_APPID_SIZE and wfAppId by extending
        OdmNullBind.
   0.20 2007-10-17-16:37 Simplified to not throw any exceptions directly
        and properly rely on the native methods to filter out ill-formed
        appId parameters.  The rejection of null appWindow parameters is
        also corrected.
   0.19 2007-03-27-20:09 Remove the extra parameter to getIodmWinNative.
        Any fussing with search paths at library load time doesn't work,
        and some of the functions only work with XP SP1 and later.  The
        solution to finding the jawt.dll and awt.dll libraries are to make
        sure that the JRE JVM is used (as happens when a .JAR is executed).
        It is still worthwhile to load jawt.dll dynamically in case it is
        not needed and in case it can't be found.  Failure should simply
        degrade and that is handled in odmjni100.dll.
   0.18 2007-03-27-18:20 Restore the static initialization to just our
        odmjni100.dll.  This dll will always be found if in the same
        directory as the application .jar file or if in the Java system
        property, java.library.path. Then modify OdmJniBind.application
        (appId, appWindow) to pass a path location to getIodmWinNative.
   0.17 2007-03-26-22:18 Try using System.load with "awt.dll" and "jawt.dll"
        but this leads to conflicts.  I wonder if I can use dynamic binding
        of jawt.dll and let that binding find the rest.  This is far more
        involved.
   0.16 2007-03-26-21:26 Modify the static operations to see if awt.dll
        can be loaded from the java.library.path.  It can't be loaded with
        loadLibrary and setting java.library.path path does not help Windows
        load the necessary component.
   0.15 2007-02-04-21:34 Make alternative application(appId, myWindow)
        entry and share common implementation beyond the initial
        native application call.
   0.14 2007-01-15-16:07 Correct reference to OdmNullBind.application to
        get clean compile.
   0.13 2007-01-15-15:22 Correct the synopsis to correctly report on the
        two public methods provided by this class.
   0.12 2007-01-15-15:01 Use OdmNullBind.application(appId) when
        getIodmNative fails in application(appId)
   0.11 2007-01-15-14:50 Remove hasConMan, hasDefaultDMS, and selectDoc,
        making them methods on OdmJniApp, which uses them privately.
   0.10 2006-12-18-14:01 Provide for possible throw of OdmError from
        the application method, and identify where the application()
        operation needs to check for well-formed Application ID.
   0.09 2006-12-18-13:19 Review for accomodation of the 0.30alpha
        practical100 interface and components.  Touch up some of the
        comments.
   0.08 2006-11-30-00:06 Add selectDoc native method.
   0.07 2006-11-29-21:46 Add hasDefaultDMS native method.
   0.06 2006-11-29-20:52 Add hasConMan native method.
   0.05 2006-11-29-18:06 Add holdNativeInterface native method.
   0.04 2006-11-29-16:56 Add note about unchecked exception needed on
        validation of appId.
   0.03 2006-11-29-12:45 Change the parameters provided to the OdmJniApp
        constructor to match its definition.
   0.02 2006-11-29-00:33 Add getIodmNative and the supporting methods.
        Have OdmJniBind.application deliver an OdmJniApp when an interface
        is obtained successfully.
   0.01 2006-11-28-18:17 Add an useful getVersion implementation that
        returns a result that we can use if we want.
   0.00 2006-11-28-14:58 Introduce "null" binding function that simply
        confirms package-level JNI binding to odmjni100.dll is
        working properly.

   $Header: /ODMdev/info/odma/odmjni100/OdmJniBind.java 23    07-11-10 15:53 Orcmid $
   */

/*             *** end of info.odma.odmjni100.OdmJniBind.java ***         */