/* OdmJniBind.java 0.14              UTF-8                  dh:2007-01-15
 *
 * 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.
 *
 * Thereare two public methods:
 *
 *      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.
 *
 * 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
{
    /* 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).
     */


    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 */



    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.
           */


    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.
           */



    public static
        info.odma.practical100.OdmConnection
            application(java.lang.String appId)
                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. */

        long rIface = getIodmNative(appId);
            /* XXX: This procedure relies on getIodmNative verifying
                    appID and not providing an interface in that case.

                    This procedure also relies on both OdmNullConnection
                    and OdmJniApp checking the appId they are provided,
                    so that this procedure does not need to verify appId.
               */

        if (getInterfaceRef(rIface) == 0)
             return info.odma.practical100.OdmNullBind.application(appId);
                /* Because we did not get an Interface. This method
                   can throw an OdmError. */

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

                info.odma.practical100.OdmConnection
                    OdmApp = new OdmJniApp(appId, 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. The appId is preserved
                       as part of the OdmNullConnection implementation
                       underneath.

                       This constructor can throw an OdmError.
                       */

                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;
                }


        }

    static

        {   /* Static initialization of this class specifies the
               loading of the only DLL that we'll use. */

            System.loadLibrary("odmjni100");

            } /* static initialization */

    } /* OdmJniBind */



/* 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 17    07-01-15 16:09 Orcmid $
   */

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