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