/* OdmJniApp.java 0.11               UTF-8                  dh:2007-01-25
 *
 * OdmJniApp is a package class that delivers an OdmConnection inter-
 * face with an OdmNative class implementation.  The class inherits from
 * OdmNullConnection.
 *
 * The constructor accepts an interface reference for an IodmApplication100
 * COM interface that is used to coordinate with OdmNative components.  The
 * lifecycle of that interface reference must be managed by the OdmJniApp
 * instance.
 *
 * Instances are constructed by OdmJniBind.application when it is determined
 * that an IodmApplication100 interface is acquired.
 */

package info.odma.odmjni100;


class OdmJniApp extends info.odma.practical100.OdmNullConnection
                implements info.odma.practical100.OdmConnection
{
    /* This is a standard class that overloads OdmNullConnection methods
       to accomplish its functions.  Native methods used to coordinate
       with ODMA are implemented with info.odma.odmjni100.OdmJniBind static
       methods and with static methods of this class.
     */

    private long rIodmNative;
        /* This is the interface reference that is held on behalf of
           the OdmConnection implementation carried in OdmJniApp.
           */

    private boolean knowConnection;
        /* True once we know the connectionAvailable() response. */

    private boolean knownConnection;
        /* The known value, once one is known.  This can be over-ridden
           by release(), whether or not previously known, because
           release() sets this false and also clears rIodmNative.
           after freeing the interface, if any.
           */

    private boolean knowDefaultDMS;
        /* True once we know the dmsDefaultAvailable() response. */

    private boolean knownDefaultDMS;
        /* The known value, once it is known.  This can be over-ridden
           by release(), in the same manner as knownConnection.
           */


    private static native boolean checkViewOnly(long rIodmWorking);
        /* Provided an IodmWorking100 interface reference, this function
           returns the result of IodmWorking100.viewOnly() as a boolean.
           */

    private static native boolean hasConMan(long rIodmNative);
        /* This native function reports whether or not OdmNative100
           has linked the ODMA Connection Manager or not.
           */



    private static native boolean hasDefaultDMS(long rIodmNative);
        /* This native function reports whether or not OdmNative100
           has acquired a Default DMS for the application or not.
           */

    private static native long
            jniNewDoc(              long rIodmNative,
                        java.lang.String docFormatName );
        /* This native function will establish a new document using the
           native connection, if possible, and return a result code
           accordingly.
           */


    private static native long selectDoc(long rIodmNative);
        /* This native function will selectDoc if it can and return
           an rIodmWorking interface reference for a working document or
           else return a result code.

           The operation returns a NULL interface reference
           a non-interface reference is provided as input.
           */



    OdmJniApp( java.lang.String appId, /* Application that's using ODMA */
                          long rIface  /* The interface to an IodmNative */
               )
        throws info.odma.practical100.OdmError

    {   /* Hold the interface for maintenance as long as other methods
           depend on its retentions.  The release procedure must make
           sure that it is released too.
              Whether or not rIface succeeded, appId will be verified
           and an unchecked exception thrown from OdmNullConnection.
           */

        super(appId);
            /* This constructor will verify whether the appId is well-
               formed and it will throw OdmError if that fails.
               */

        rIodmNative =
            info.odma.odmjni100.OdmJniBind.holdNativeInterface
                ( info.odma.odmjni100.OdmJniBind.getInterfaceRef(rIface) );
            /* so that rIodmNative is either 0 or a reference */

        knowConnection = false;
            /* We don't know yet and we'll figure it out when asked. */

        knownConnection = false;
            /* Safety-measure superstition */

        knowDefaultDMS = false;

        knownDefaultDMS = false;
            /* Ditto for dmsDefaultAvailable information */

        } /* OdmJniApp */



    /* OdmInterface Interface Method Implementations
     * ---------------------------------------------
     */

    public java.lang.String interfaceImplementation()
    {   /* Return a text string describing this implementation */

        return "ODMJNI 1.0 OdmJniApp 0.11 OdmConnection";

        /* The default toString() identifies the object but does not
           provide anything apart from the class name of the implementation.
           This result is intended to be more useful in trouble-shooting
           and identification of implementation version in problem analysis.
           */

        } /* interfaceImplementation */



    public boolean available()
    {   /* True when ODMA is available for use.

           When the result is false, all operations provide their null
           behavior.

           This is similar to the implementation of the
           IodmNative100::hasConMan() method, except that release can
           change the known response.
           */

    if (!knowConnection)
        {   knowConnection = true;
                /* We are about to know, either way. */
            if (rIodmNative == 0)
                 knownConnection = false;
                    /* Because not possible without the interface */
            else knownConnection = hasConMan(rIodmNative);
                    /* defining having a connection as equivalent to
                       having the ODMA Connection Manager available.
                       */
            }

    return knownConnection;

    } /* available */



    public void release()
    {   /* If a native interface is being held, it must be released
           now. */

        if (rIodmNative != 0)
             info.odma.odmjni100.OdmJniBind.freeNativeInterface
                 (rIodmNative);
        rIodmNative = 0;

        knownConnection = false;
            /* and it now stays that way until finalize(). */

        knownDefaultDMS = false;
            /* And this stays that way until finalize() too. */

        /* Other release operations go in here. */

        super.release();

        } /* release */



    protected void finalize()
                   throws Throwable
    {   /* We must do this, in case this object becomes inaccessible
           without release() having been performed.  This is how
           we intend to clean up after ourselves no matter what.

           The throw clause is required by finalize() inheritance from
           java.lang.Object.  No checked exceptions arise from the
           implementation here.
           */

        release();

        super.finalize();

        } /* finalize */


     /* OdmConnection Interface Method Implementations
     * ----------------------------------------------
     */


    public boolean dmsDefaultAvailable()
    {   /* This method behaves similarly to available().
           The first time we are asked, we find out if that is
           the case.  We give the same answer thereafter, and
           that answer will be changed by release() since the
           IodmNative interface is released and the methods of
           this interface implementation instance have no default
           DMS available thereafter.

           This is similar to IodmApplication100::hadDefaultDMS.
           */

        if (!knowDefaultDMS)
        {   knowDefaultDMS = true;
                /* We are about to know, either way. */
            if (!available())
                 knownDefaultDMS = false;
                    /* Because not possible without the connection */
            else knownDefaultDMS = hasDefaultDMS(rIodmNative);
            }

        return knownDefaultDMS;

        } /* dmsDefaultAvailable */



    public info.odma.practical100.OdmPendingDocument
                acceptNewDocument(java.lang.String docFormatName)
                        throws info.odma.practical100.OdmError

    {   /* Return an OdmPendingDocument based on the result of the
           odmjni native newDoc() operation.

           The results are handled as follows:

                0   ODM_SUCCESS (but non-null Interface reference)
                    return an OdmJniPend result with that interface

                2   ODM_E_CANCEL
                    return nullDocument.pendingCancelled()

                6   ODM_E_APPSELECT
                    return nullDocument.pendingLocalOperation()

            other   same as ODM_E_FAIL (1)
                    return nullDocument.workingFailed()
           */

           /* FIXME: This function should verify the format parameter
                     before it does anything else.
                     */

        if (!dmsDefaultAvailable())
             return super.acceptNewDocument(docFormatName);
                /* If we don't have a dms, then we are not going
                   anywhere but to the null response.
                   */

        long rIpend = jniNewDoc(rIodmNative, docFormatName);

        int iStatus =
                info.odma.odmjni100.OdmJniBind.getInterfaceStatus(rIpend);

        if (rIpend == 0 || iStatus > 0)

             switch (iStatus)
             {  case(2):
                     return nullDocument.pendingCancelled();
                case(6):
                     return nullDocument.pendingLocalOperation();
                default:
                     return nullDocument.pendingFailed();
                }

        /* We have a successful result.  Deliver it to the application
           as an OdmJniPend OdmPendingDocument implementation.
           */

        info.odma.practical100.OdmPendingDocument odmPending = null;

        try
        {   odmPending = new info.odma.odmjni100.OdmJniPend
                                   ( rIpend, nullDocument);
            }
        catch (java.lang.Throwable e) {  }

        info.odma.odmjni100.OdmJniBind.freeNativeInterface(rIpend);

        if (odmPending == null)
             return nullDocument.pendingFailed();

        return odmPending;

        } /* acceptNewDocument */



    public info.odma.practical100.OdmWorkingDocument
                chooseDocument()

    {   /* Return an OdmWorkingDocument based on the result of the
           odmjni native selectDoc() operation.

           The results are handled as follows:

                0   ODM_SUCCESS (but non-null Interface reference)
                    return an OdmJniView result with that interface

                2   ODM_E_CANCEL
                    return nullDocument.workingCancelled()

                6   ODM_E_APPSELECT
                    return nullDocument.workingLocalOperation()

            other   same as ODM_E_FAIL (1)
                    return nullDocument.workingFailed()
           */

        if (!dmsDefaultAvailable())
             return super.chooseDocument();
                /* If we don't have a dms, then we are not going
                   anywhere but to the null response.
                   */

        long rIchoice = selectDoc(rIodmNative);

        int iStatus =
                info.odma.odmjni100.OdmJniBind.getInterfaceStatus(rIchoice);

        if (rIchoice == 0 || iStatus > 0)

             switch (iStatus)
             {  case(2):
                     return nullDocument.workingCancelled();
                case(6):
                     return nullDocument.workingLocalOperation();
                default:
                     return nullDocument.workingFailed();
                }

        /* We have a successful result.  Deliver it to the application
           as an OdmJniView OdmWorkingDocument implementation.
           */

        info.odma.practical100.OdmWorkingDocument rIwork = null;

        try
        {   if (checkViewOnly(rIchoice))
                 rIwork = new info.odma.odmjni100.OdmJniView
                                   ( rIchoice, nullDocument);
            else rIwork = new info.odma.odmjni100.OdmJniWork
                                   ( rIchoice, nullDocument);
              /* delivering modifiable or read-only implementations
                 as required by the delivered choice.
                 */
            }
        catch (java.lang.Throwable e) { rIwork = null; }

        info.odma.odmjni100.OdmJniBind.freeNativeInterface(rIchoice);

        if (rIwork == null)
             return nullDocument.workingFailed();

        return rIwork;

        } /* chooseDocument */




    static

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

            System.loadLibrary("odmjni100");

            } /* static initialization */


    } /* OdmJniApp */


/* 0.11 2007-01-25-15:23 Correct leaking interface in acceptNewDoc()
   0.10 2007-01-20-17:28 Add acceptNewDocument implementation, following
        the pattern of chooseDocument which is of exactly the same pattern.
   0.09 2007-01-15-14:53 Add hasConMan, hasDefaultDMS, and selectDoc as
        private native methods that are used exclusively by OdmJniApp for
        implementation of the OdmConnection interface to ODMJNI 1.0.
   0.08 2007-01-12-14:37 Add the checkViewOnly private static native method.
        Use odmjni100.dll as the implementation DLL.  This is the first
        step of refactoring the declaration of native methods onto the
        classes that they should be private to.  chooseDocument is updated
        to return viewable-only or modifiable document content as needed.
   0.07 2007-01-07-21:30 Implement full chooseDocument functionality, with
        additional touch-ups noticed since 0.25alpha. As the native
        selectDoc function is improved, the difference will automatically
        show up here.  This chooseDocument always produces a viewOnly
        Working Document until we have OdmJniWrk in 0.40alpha.
   0.06 2006-12-18-21:29 Adjust to use of OdmNullCache in NullDocument
        and used here by inheritance.  This class is 1,751 bytes and it
        doesn't appear that size is going to be an issue.
   0.05 2006-12-18-13:34 Review and adjust for operation with the 0.30alpha
        versions of practical100 and use in the 0.25alpha regression use of
        odmjni100.
   0.04 2006-11-29-23:45 Add skeletal chooseDocument() enough to get
        selects to be performed but we only return null working documents.
   0.03 2006-11-29-21:37 Implement the dmsDefaultAvailable() behavior.
   0.02 2006-11-29-19:44 Implement the connectionAvailable() behavior.
   0.01 2006-11-29-17:19 Hold the supplied interface and manage its
        life-cycle.
   0.00 2006-11-29-12:20 Introduce nearly-null case that confirms the
        correct employment of OdmJniApp objects when OdmNative is bound
        by OdmJniBind.application.  The delivered interface reference is
        not used, so it will have been released by OdmJniBind.application.

   $Header: /ODMdev/info/odma/odmjni100/OdmJniApp.java 12    07-01-25 15:56 Orcmid $
   */

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