# LockType.java

    /*
    ** Module   : LockType.java
    ** Abstract : Helper class which defines possible lock types
    **
    ** Copyright (c) 2004-2017, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -T- --JPRM-- --------------------------Description---------------------------
    ** 001 ECF 20051010 ADD   @23046 Created initial version. Defines possible lock types for
    **                               Progress-like, pessimistic record locking.
    ** 002 ECF 20051110 CHG   @23308 Implement Comparable interface. The compareTo implementation
    **                               compares the restrictiveness of this lock type to another. Lock
    **                               types that are more restrictive sort higher.
    ** 003 ECF 20060728 CHG   @28268 Added toNoWait() method and internal constants.
    ** 004 ECF 20070412 CHG   @32982 Rationalized API. Renamed toNoWait() method
    **                               to toNoWaitVariant() and added symmetric API toWaitVariant().
    ** 005 ECF 20071128 CHG   @36052 Changed internal variables to drop noWait boolean. Use negative
    **                               type constants for no-wait variants instead. Added static
    **                               methods toInt() and fromInt() to report internal type value and
    **                               return static LockType constant for a given type value,
    **                               respectively. Implement generic Comparable.
    ** 006 VMN 20130207              Changed values of constants LT_NONE, LT_SHARE, LT_EXCLUSIVE,
    **                               LT_NO_WAIT corresponding to their 4GL internal values and
    **                               method compareTo(...) is corrected.
    ** 007 VMN 20130311              Added method fromLockNowait(...)
    ** 008 ECF 20131028              Moved to lock sub-package.
    ** 009 OM  20140122              Added TODO for processing errors.
    ** 010 VMN 20140330              Added errors processing.
    ** 012 OM  20150119              Added fromString() public static method.
    */
    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.persist.lock;

    /**
     * Defines as public constants the possible lock types for pessimistic
     * locking using the Progress semantic:  NONE, SHARE, EXCLUSIVE,
     * SHARE_NO_WAIT, and EXCLUSIVE_NO_WAIT.
     */
    public final class LockType
    implements Comparable<LockType>
    {
       /** Internal constant for lock type NONE, corresponds to 4GL internal value */
       public static final int LT_NONE = 6209;

       /** Internal constant for lock type SHARE, corresponds to 4GL internal value  */
       public static final int LT_SHARE = 6208;

       /** Internal constant for lock type EXCLUSIVE, corresponds to 4GL internal value  */
       public static final int LT_EXCLUSIVE = 6207;

       /** Internal constant for NO-WAIT, corresponds to 4GL internal value  */
       public static final int LT_NO_WAIT = 6090;

       /** The lack of a record lock */
       public static final LockType NONE = new LockType(LT_NONE);

       /** Progress-style share lock;  request for this type may block */
       public static final LockType SHARE = new LockType(LT_SHARE);

       /** Progress-style exclusive lock;  request for this type may block */
       public static final LockType EXCLUSIVE = new LockType(LT_EXCLUSIVE);

       /** Progress-style share lock;  requests for this type never block */
       public static final LockType SHARE_NO_WAIT = new LockType(-LT_SHARE);

       /** Progress-style exclusive lock;  requests for this type never block */
       public static final LockType EXCLUSIVE_NO_WAIT = new LockType(-LT_EXCLUSIVE);

       /** Internal type */
       private final int type;

       /**
        * Private constructor to ensure the only instances of this class are the
        * public constants.
        *
        * @param   type
        *          Internal type, used for comparisons.
        */
       private LockType(int type)
       {
          this.type = type;
       }

       /**
        * Return the internal type of the lock as an integer.
        * <p>
        * This is intended to support optimized network serialization and prevent
        * propagation of multiple instances of this class for each lock type.
        *
        * @param   lockType
        *          Instance of this class for which the type is desired.
        *
        * @return  Internal type integer stored in <code>lockType</code>.
        */
       public static int toInt(LockType lockType)
       {
          return lockType.type;
       }

       /**
        * Return the appropriate static "constant" instance of this class for the
        * given internal type.
        * <p>
        * This is intended to support optimized network serialization and prevent
        * propagation of multiple instances of this class for each lock type.
        *
        * @param   type
        *          Integer value representing one of the valid lock types.
        *
        * @return  Associated <code>LockType</code> constant.
        *
        * @throws  IllegalArgumentException
        *          if <code>type</code> is not a valid internal lock type.
        */
       public static LockType fromInt(int type)
       {
          switch (type)
          {
             case LT_NONE:
                return NONE;
             case LT_SHARE:
                return SHARE;
             case LT_EXCLUSIVE:
                return EXCLUSIVE;
             case -LT_SHARE:
                return SHARE_NO_WAIT;
             case -LT_EXCLUSIVE:
                return EXCLUSIVE_NO_WAIT;
             default:
                throw new IllegalArgumentException("Invalid lock type:  " + type);
          }
       }

       /**
        * Return the appropriate static "constant" instance of this class for the
        * given internal lock and nowait.
        * <p>
        * This is intended to support optimized network serialization and prevent
        * propagation of multiple instances of this class for each lock type.
        *
        * @param   lock
        *          Integer value.
        * @param   nowait
        *          Integer value.
        *
        * @return  Associated <code>LockType</code> constant.
        *
        * @throws  LockTypeException
        *          if arguments <code>lock</code> and <code>nowait</code> do not correspond
        *          to a valid lock type.
        */
       public static LockType fromLockNowait(long lock, long nowait)
       throws LockTypeException
       {
          boolean lockCorrect = (lock == LT_NONE || lock == LT_SHARE || lock == LT_EXCLUSIVE);
          boolean nowaitCorrect = (nowait == 0 || nowait == LT_NO_WAIT);

          if (!lockCorrect || !nowaitCorrect)
          {
             throw new LockTypeException(lockCorrect, nowaitCorrect);
          }

          if (lock == LT_NONE)
          {
             return NONE;
          }
          else if (lock == LT_SHARE)
          {
             return nowait == 0 ? SHARE : SHARE_NO_WAIT;
          }
          else
          {
             return nowait == 0 ? EXCLUSIVE : EXCLUSIVE_NO_WAIT;
          }
       }

       /**
        * Indicate whether this is a "no-wait" lock type.  A request for such a
        * lock type will never block waiting to obtain the lock, but will error
        * out instead.
        *
        * @return  <code>true</code> if lock is no-wait type, else
        *          <code>false</code>.
        */
       public boolean isNoWait()
       {
          return (type < 0);
       }

       /**
        * Indicate whether this lock type is a share lock type, ignoring its
        * no-wait designation.
        *
        * @return  <code>true</code> if this type is one of the share variants,
        *          else <code>false</code>.
        */
       public boolean isShare()
       {
          return (Math.abs(type) == LT_SHARE);
       }

       /**
        * Indicate whether this lock type is an exclusive lock type, ignoring its
        * no-wait designation.
        *
        * @return  <code>true</code> if this type is one of the exclusive
        *          variants, else <code>false</code>.
        */
       public boolean isExclusive()
       {
          return (Math.abs(type) == LT_EXCLUSIVE);
       }

       /**
        * Get the no-wait equivalent for this lock type.  If this object already
        * has the no-wait flag set, this instance is returned.  In any case, this
        * method always will return one of the public instances rather than
        * creating a new object.
        *
        * @return  <code>LockType</code> object with the same type as this object,
        *          but with the no-wait flag set, or this object if it already
        *          has the no-wait flag set or is type <code>NONE</code>.
        */
       public LockType toNoWaitVariant()
       {
          switch (type)
          {
             case LT_NONE:
                return NONE;
             case LT_SHARE:
             case -LT_SHARE:
                return SHARE_NO_WAIT;
             case LT_EXCLUSIVE:
             case -LT_EXCLUSIVE:
                return EXCLUSIVE_NO_WAIT;
             default:
                return this;
          }
       }

       /**
        * Get the waiting variant for this lock type.  If this object already has
        * the no-wait flag unset, this instance is returned.  In any case, this
        * method always will return one of the public instances rather than
        * creating a new object.
        *
        * @return  <code>LockType</code> object with the same type as this object,
        *          but with the no-wait flag unset, or this object if it already
        *          has the no-wait flag unset or is type <code>NONE</code>.
        */
       public LockType toWaitVariant()
       {
          switch (type)
          {
             case LT_NONE:
                return NONE;
             case LT_SHARE:
             case -LT_SHARE:
                return SHARE;
             case LT_EXCLUSIVE:
             case -LT_EXCLUSIVE:
                return EXCLUSIVE;
             default:
                return this;
          }
       }

       /**
        * Compare the restrictiveness of this lock type to another.  Wait and
        * no-wait variants of the same lock type category are considered equally
        * restrictive for the purpose of this comparison.
        *
        * @param   other
        *          Another <code>LockType</code> instance to compare with this one.
        *
        * @return  &gt; 0 if this lock type is more restrictive than <code>other</code>;
        *          &lt; 0 if this lock type is less restrictive than <code>other</code>;
        *          0 if they are equally restrictive.
        */
       public int compareTo(LockType other)
       {
          // based on new values: 6209, 6208, 6207 above
          return (Math.abs(other.type) - Math.abs(type));
       }

       /**
        * Compose a string representation of this object for assistance in debugging and testing.
        *
        * @return  String representation of this object's internal state.
        */
       public String toString()
       {
          switch (type)
          {
             case LT_NONE:
                return "NONE";
             case LT_SHARE:
                return "SHARE";
             case -LT_SHARE:
                return "SHARE_NO_WAIT";
             case LT_EXCLUSIVE:
                return "EXCLUSIVE";
             case -LT_EXCLUSIVE:
                return "EXCLUSIVE_NO_WAIT";
             default:
                return "ERROR";
          }
       }

       /**
        * Obtain the locking type object from a string representation. All unqualified,
        * class-qualified and fully qualified string representation of the objects are supported.
        * If the input string does not match any locking types, null is returned.
        *
        * @param   str
        *          The string representation of a LockType object.
        *
        * @return  the locking type instance represented by the input string if it can be parsed,
        *          otherwise null is returned.
        */
       public static LockType fromString(String str)
       {
          if (str == null || str.isEmpty())
          {
             return null;
          }
          switch (str)
          {
             case "com.goldencode.p2j.persist.lock.LockType.NONE":
             case "LockType.NONE":
             case "NONE":
                return LockType.NONE;

             case "com.goldencode.p2j.persist.lock.LockType.SHARE":
             case "LockType.SHARE":
             case "SHARE":
                return LockType.SHARE;

             case "com.goldencode.p2j.persist.lock.LockType.EXCLUSIVE":
             case "LockType.EXCLUSIVE":
             case "EXCLUSIVE":
                return LockType.EXCLUSIVE;

             case "com.goldencode.p2j.persist.lock.LockType.SHARE_NO_WAIT":
             case "LockType.SHARE_NO_WAIT":
             case "SHARE_NO_WAIT":
                return LockType.SHARE_NO_WAIT;

             case "com.goldencode.p2j.persist.lock.LockType.EXCLUSIVE_NO_WAIT":
             case "LockType.EXCLUSIVE_NO_WAIT":
             case "EXCLUSIVE_NO_WAIT":
                return LockType.EXCLUSIVE_NO_WAIT;

             default:
                return null;
          }
       }
    }