docs: @Override
      public final void unlock(final long lockID, final Transaction transaction, final boolean incrementUnlockCountIfNonpersistent) throws ProtocolException, TransactionException, SevereMessageStoreException
      {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.entry(this, tc, "unlock", new Object[] { Long.valueOf(lockID), transaction, Boolean.valueOf(incrementUnlockCountIfNonpersistent) });
  
          boolean invokeUnlockedCallback = false;
          boolean linkHasBecomeAvailable = false;
          boolean linkHasBecomeReleasable = false;
          boolean linkHasBecomeNotReleasable = false;
          boolean requiresPersistUnlockTask = false;
          AbstractItem item = null;
          synchronized (this)
          {
              if (_itemLinkState == ItemLinkState.STATE_LOCKED)
              {
                  if (_lockID != lockID)
                  {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled())
                          SibTr.event(this, tc, "LockID mismatch! LockID(Item): " + _lockID + ", LockID(New): " + lockID);
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                          SibTr.exit(this, tc, "unlock");
                      throw new LockIdMismatch(_lockID, lockID);
                  }
  
                  if (null != transaction)
                  {
                      _transactionId = transaction.getPersistentTranId();
                  }
  
                  if (_lockID == Item.DELIVERY_DELAY_LOCK_ID) { // For Delivery delay messages
  
                      // Fetch the item from persistance if not available
                      // This is needed because we need to call item.eventUnlocked()
                      // so that if there is any ready consumer we can deliver the 
                      // message immediately
                      item = getItem();
                      ListStatistics stats = getParentStatistics();
                      synchronized (stats)
                      {
                          stats.decrementLocked();
                          stats.incrementAvailable();
                      }
  
                      // we can make the item discardable 
                      // since we have fetched the item
                      linkHasBecomeReleasable = _declareDiscardable();
                      _lockID = NO_LOCK_ID;
                      _tuple.setLockID(AbstractItem.NO_LOCK_ID);
                      if (incrementUnlockCountIfNonpersistent)
                      {
                          _unlockCount++;
                      }
                      _itemLinkState = ItemLinkState.STATE_AVAILABLE;
                      invokeUnlockedCallback = true;
                      linkHasBecomeAvailable = true;
                  } else
                  {
                      item = _getAndAssertItem();
  
                      ListStatistics stats = getParentStatistics();
                      synchronized (stats)
                      {
                          stats.decrementLocked();
                          stats.incrementAvailable();
                      }
  
                      linkHasBecomeReleasable = _declareDiscardable();
                      _lockID = NO_LOCK_ID;
                      _tuple.setLockID(AbstractItem.NO_LOCK_ID);
                      if (incrementUnlockCountIfNonpersistent)
                      {
                          _unlockCount++;
                      }
                      _itemLinkState = ItemLinkState.STATE_AVAILABLE;
                      invokeUnlockedCallback = true;
                      linkHasBecomeAvailable = true;
                  }
              }
              else if (_itemLinkState == ItemLinkState.STATE_PERSISTENTLY_LOCKED)
              {
                  if (_lockID != lockID)
                  {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled())
                          SibTr.event(this, tc, "LockID mismatch! LockID(Item): " + _lockID + ", LockID(New): " + lockID);
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                          SibTr.exit(this, tc, "unlock");
                      throw new LockIdMismatch(_lockID, lockID);
                  }
  
                  if (null == transaction)
                  {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled())
                          SibTr.event(this, tc, "No transaction supplied for persistent unlock!");
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                          SibTr.exit(this, tc, "unlock");
                      throw new StateException("Unlock of Persistently locked requires transaction");
                  }
  
                  _transactionId = transaction.getPersistentTranId();
                  linkHasBecomeNotReleasable = _declareNotDiscardable(_getItemNoRestore());
                  _tuple.setLockID(AbstractItem.NO_LOCK_ID);
                  _itemLinkState = ItemLinkState.STATE_UNLOCKING_PERSISTENTLY_LOCKED;
                  requiresPersistUnlockTask = true;
              }
              else
              {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled())
                      SibTr.event(this, tc, "Invalid Item state: " + _itemLinkState);
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                      SibTr.exit(this, tc, "unlock");
                  throw new StateException(_itemLinkState.toString());
              }
          }
          // this needs to be outside sync block
          if (linkHasBecomeReleasable)
          {
              _declareReleasable(_getItemNoRestore());
          }
          if (linkHasBecomeNotReleasable)
          {
              _declareNotReleasable();
          }
          if (requiresPersistUnlockTask)
          {
              Task task = new PersistUnlock(this);
              ((PersistentTransaction) transaction).addWork(task);
          }
          if (linkHasBecomeAvailable && isAvailable())
          {
              if (null != _owningStreamLink)
              {
                  _owningStreamLink.linkAvailable(this);
              }
          }
          // this needs to be outside sync block
          if (invokeUnlockedCallback)
          {
              if (item != null)
              {
                  item.eventUnlocked();
              }
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.exit(this, tc, "unlock");
      }