docs: @Override
      public JsMessage receive(long originalTimeout,
                               TransactionCommon transaction)
                      throws SISessionUnavailableException,
                      SIIncorrectCallException,
                      SIResourceException,
                      SINotPossibleInCurrentConfigurationException
      {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.entry(
                          tc,
                          "receive",
                          new Object[] { this, Long.valueOf(originalTimeout), transaction });
  
          if (transaction != null && !transaction.isAlive())
          {
              SIIncorrectCallException e = new SIIncorrectCallException(nls.getFormattedMessage(
                                                                                                "TRANSACTION_RECEIVE_USAGE_ERROR_CWSIP0777",
                                                                                                new Object[] { _destinationAttachedTo },
                                                                                                null));
  
              if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled())
                  SibTr.exception(tc, e);
  
              if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                  SibTr.exit(tc, "receive", e);
  
              throw e;
          }
  
          //indicates if we should continue to wait for a message or not
          boolean timeToRun = true;
          SIMPMessage msg = null;
  
          long timeout = originalTimeout;
          //The time we start this call
          long startTimeMillis = java.lang.System.currentTimeMillis();
          long currentTimeMillis = startTimeMillis;
  
          // This is used to tell if we have locked the message by removing
          // it from the item stream.  This will allow us later to remove the
          // message from the item stream and unlock it.
          boolean messageLocked = false;
          // Used to tell if we passed the message straight through
          // without touching an itemstream
          boolean wasMessageOnStream = false;
  
          //Local tran was created for this receive
          boolean localTranCreated = false;
          LocalTransaction localTran = null;
  
          //while we should still be waiting for a message
          while (timeToRun)
          {
              // Synchronize to check and modify consumer state
              this.lock();
              try
              {
                  // Check that this consumer can receive the message.
                  checkReceiveState();
  
                  // If message ordering is required, throw exception if current receive on a different tran is active
                  if (_destinationAttachedTo.isOrdered() && !_consumerDispatcher.isNewTransactionAllowed(transaction))
                  {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                          SibTr.exit(tc, "receive", "SISessionUnavailableException - transaction active");
  
                      throw new SISessionUnavailableException(
                                      nls.getFormattedMessage(
                                                              "ORDERED_TRANSACTED_RECEIVE_ERROR_CWSIP0180",
                                                              new Object[] {
                                                                            _destinationAttachedTo.getName(),
                                                                            _messageProcessor.getMessagingEngineName() },
                                                              null));
  
                      // suspendConsumer(SUSPEND_FLAG_TRAN_ACTIVE);
                  }
  
                  //Shows that this is a synchronous consumer waiting for a message
                  _waiting = true;
                  //if this was intended by the caller as a non-transactional operation,
                  //then it is not recoverable
                  if (transaction == null)
                  {
                      _transacted = false;
                  }
                  else
                  {
                      _transacted = true;
                  }
                  //if this LCP is stopped when the receive call is made then we can't look for messages
                  //just yet. However, we could still begin looking for a message when we are started,
                  //assuming we haven't run out of time
                  if (_stopped || (_suspendFlags & SUSPEND_FLAG_RETRY_TIMER) > 0)
                  {
                      _waitingToStart = true;
                  }
                  else
                  {
                      //at this point we know we're not closed or stopped and we know there isn't an
                      //AsynchConsumerCalback registered, so we're definitely ready to receive a message
                      setReady();
                      //attempt to retrieve an eligible message in a locked state
                      msg = getEligibleMsgLocked(transaction);
  
                      if (msg != null)
                      {
                          // Indicate that we have locked the message by getting it.
                          messageLocked = true;
                          timeToRun = false;
                          unsetReady();
                      }
                  }
  
                  // If we don't have a message we may have to wait for one to arrive.
                  // If consuming remote from the destination the Cd will be interested
                  // in this nugget of information (even if we're not planning on waiting)
                  // When running locally this is a no-op
                  // 512943.1 - if gathering, we may have got no msg back but still need to 
                  // call waiting to initiate prefils to the remote DMEs
                  if (msg == null || _gatherMessages)
                  {
                      timeout = _consumerKey.waiting(timeout, true);
                      // If we do a remote get with no wait - we need to wait at least
                      // the time of the roundTripTime (minus the time taken to get here)
                      if (originalTimeout == LocalConsumerPoint.NO_WAIT)
                          originalTimeout = timeout - (System.currentTimeMillis() - startTimeMillis);
                  }
  
                  //First time through, we've checked for a message once, if the timeout is set
                  //to NO_WAIT then indicate that we're not going to wait for a message to
                  //turn up
                  if (timeout == LocalConsumerPoint.NO_WAIT)
                  {
                      timeToRun = false;
                  }
                  //if we haven't got a message yet and we are prepared to wait a bit
                  //longer for one to turn up
                  if (msg == null && timeToRun)
                  {
                      try
                      {
                          //wait for the specified time
                          if (timeout == LocalConsumerPoint.INFINITE_WAIT)
                              _waiter.await();
                          else
                              _waiter.await(timeout, TimeUnit.MILLISECONDS);
                      } catch (InterruptedException e)
                      {
                          // No FFDC code needed
                          // No message arrived so return null
                      }
                  }
  
                  //we're not waiting any longer
                  _waitingToStart = false;
                  _waiting = false;
                  //we're not ready for any more messages
                  unsetReady();
  
                  //Have we been woken up with a message?
                  if (_msgAttached)
                  {
                      wasMessageOnStream = _msgOnItemStream;
                      //attempt to retrieve the message in a locked state
                      msg = getAttachedMessage();
  
                      //if we got a message successfully then don't bother waiting any longer
                      if (msg != null)
                      {
                          // If the message was on the item stream
                          // then we would have locked it from the getAttachedMessage() call
                          if (wasMessageOnStream)
                              messageLocked = true;
  
                          timeToRun = false;
                      }
                  }
                  // If we didn't get a message, maybe we were interupted with an exception.
                  else if (_notifiedException != null)
                  {
                      Throwable e = _notifiedException;
                      _notifiedException = null;
  
                      SibTr.exception(tc, e);
  
                      if (e instanceof SISessionUnavailableException)
                      {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "receive", e);
  
                          throw (SISessionUnavailableException) e;
                      }
                      else if (e instanceof SIIncorrectCallException)
                      {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "receive", e);
  
                          throw (SIIncorrectCallException) e;
                      }
                      else if (e instanceof SIResourceException)
                      {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "receive", e);
  
                          throw (SIResourceException) e;
                      }
                      else if (e instanceof SINotPossibleInCurrentConfigurationException)
                      {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "receive", e);
  
                          throw (SINotPossibleInCurrentConfigurationException) e;
                      }
                      else
                      {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "receive", e);
  
                          throw new SIErrorException(e);
                      }
                  }
              } // synchronized
              finally
              {
                  this.unlock();
              }
  
              //if we still want to wait some more and the original timeout wasn't infinite (i.e. 0)
              if (timeToRun && timeout != LocalConsumerPoint.INFINITE_WAIT)
              {
                  //the time left to wait is the originalTimeout minus the difference
                  //between now and when we starte
                  currentTimeMillis = java.lang.System.currentTimeMillis();
                  timeout = originalTimeout - (currentTimeMillis - startTimeMillis);
  
                  //if there is no time left to wait
                  if (timeout <= 0)
                  {
                      //then don't wait any longer!
                      timeToRun = false;
                  }
              }
          }
  
          JsMessage returnMsg = null;
  
          if (msg != null)
          {
  
              try
              {
                  // Copy the message for receive when the connection indicates that it should.
                  // If the message was not on the ItemStream there is no chance of the consumer
                  // fiddling with the message then backing out, in which case there is no need
                  // to copy it.
                  // Make another copy if we are pub/sub
                  if ((messageLocked || _consumerDispatcher.isPubSub()) && ((ConnectionImpl) (_consumerSession.getConnection())).getMessageCopiedWhenReceived())
                      returnMsg = msg.getMessage().getReceived();
                  else
                      returnMsg = msg.getMessage();
              } catch (MessageCopyFailedException e)
              {
                  FFDCFilter.processException(
                                              e,
                                              "com.ibm.ws.sib.processor.impl.JSLocalConsumerPoint.receive",
                                              "1:1856:1.22.5.1",
                                              this);
  
                  SibTr.error(tc, "INTERNAL_MESSAGING_ERROR_CWSIP0002",
                              new Object[] {
                                            "com.ibm.ws.sib.processor.impl.JSLocalConsumerPoint",
                                            "1:1862:1.22.5.1",
                                            SIMPUtils.getStackTrace(e) });
  
                  SibTr.exception(tc, e);
  
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                      SibTr.exit(tc, "receive", e);
  
                  throw new SIResourceException(
                                  nls.getFormattedMessage(
                                                          "INTERNAL_MESSAGING_ERROR_CWSIP0002",
                                                          new Object[] {
                                                                        "com.ibm.ws.sib.processor.impl.JSLocalConsumerPoint",
                                                                        "1:1875:1.22.5.1",
                                                                        e },
                                                          null),
                                  e);
              }
  
              if (!msg.isItemReference())
              {
                  if ((msg.getReportCOD() != null) || (msg.isFromRemoteME()))
                  {
                      // If the message wasn't in the MS we can't rely on a callback
                      // to drive the report, instead we drive it ourselves
                      if (!messageLocked)
                          ((MessageItem) msg).beforeCompletion(_autoCommitTransaction);
                      else
                      {
                          // If the message is not transacted and a report message is
                          // required, we cant use the cached auto-commit transaction
                          // so we create a local transaction to use
                          if (transaction == null)
                          {
                              localTran = _txManager.createLocalTransaction(false);
                              transaction = localTran;
                              localTranCreated = true;
                          }
  
                          transaction.registerCallback(msg);
  
                      }
                  }
              }
  
              // Set underlying message attributes if there's a chance of them being
              // different from the defaults
              if ((returnMsg != null) && messageLocked)
              {
                  //set the redeliveredCount if required
                  if (msg.guessRedeliveredCount() != 0)
                      returnMsg.setRedeliveredCount(msg.guessRedeliveredCount());
  
                  // Calculate the message wait time
                  // NB: Idealy we'd only do this if we knew stats was on, or we needed
                  //     it in the message but we don't have the stats information
                  //     available to us here.
                  long waitTime = msg.updateStatisticsMessageWaitTime();
  
                  //Only store wait time in message for mediations or when
                  // explicitly asked for
                  if (((ConnectionImpl) (_consumerSession.getConnection())).getSetWaitTimeInMessage())
                  {
                      returnMsg.setMessageWaitTime(waitTime);
                  }
  
              }
  
              //We have successfully obtained a locked message,
              //get it out of the CD's itemStream and pass it back to the consumer
              try
              {
                  //Remove the message from the itemstream if the message was locked
                  if (messageLocked)
                  {
                      // If no transaction was supplied, then use the cached one.
                      if (transaction == null)
                      {
                          transaction = _autoCommitTransaction;
                      }
  
                      Transaction msTran = _messageProcessor.resolveAndEnlistMsgStoreTransaction(transaction);
  
                      // set currentTransaction to be the one in use
                      if (_destinationAttachedTo.isOrdered())
                          _consumerDispatcher.setCurrentTransaction(transaction, null);
  
                      // maxActiveMessages on the consumer is only for use with asynch consumers but if this
                      // consumer is a member of a ConsumerSet then it'll be keeping track of all active messages
                      // across the set so we need to register with the tran to make sure the count is decremented
                      // when this transaction is committed/rolled back.
                      // We will also have incremented our count if we were previously a bifurcatable async consumer 
                      if (_consumerKey.getConsumerSet() != null ||
                          (_bifurcatable && (_maxActiveMessages != 0)))
                          transaction.registerCallback(this);
  
                      msg.remove(msTran, _consumerKey.getGetCursor(msg).getLockID()); // 172968
  
                      if (localTranCreated)
                      {
                          localTran.commit();
                          transaction = null;
                      }
                  }
                  // If the message never got into the message store we'll still have incremented the active
                  // mesasge count on any ConsumerSet we're a member of, so we must decrement it here (as
                  // there's no transaction to use the commit/rollback of.
                  // We will also have incremented our count if we were previously a bifurcatable async consumer 
                  else if (_consumerKey.getConsumerSet() != null ||
                           (_bifurcatable && (_maxActiveMessages != 0)))
                      removeActiveMessages(1);
              } catch (MessageStoreException e)
              {
                  // MessageStoreException shouldn't occur so FFDC.
                  FFDCFilter.processException(
                                              e,
                                              "com.ibm.ws.sib.processor.impl.JSLocalConsumerPoint.receive",
                                              "1:2010:1.22.5.1",
                                              this);
  
                  SibTr.exception(tc, e);
  
                  SibTr.error(tc, "INTERNAL_MESSAGING_ERROR_CWSIP0003",
                              new Object[] {
                                            "com.ibm.ws.sib.processor.impl.JSLocalConsumerPoint",
                                            "1:2018:1.22.5.1",
                                            SIMPUtils.getStackTrace(e),
                                            _consumerDispatcher.getDestination().getName() });
  
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                      SibTr.exit(tc, "receive", e);
  
                  throw new SIResourceException(
                                  nls.getFormattedMessage(
                                                          "INTERNAL_MESSAGING_ERROR_CWSIP0003",
                                                          new Object[] {
                                                                        "com.ibm.ws.sib.processor.impl.JSLocalConsumerPoint",
                                                                        "1:2030:1.22.5.1",
                                                                        e,
                                                                        _consumerDispatcher.getDestination().getName() },
                                                          null),
                                  e);
              }
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() &&
              (returnMsg != null))
              SibTr.debug(this, tc, "verboseMsg OUT : " + returnMsg.toVerboseString());
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.exit(tc, "receive", msg);
  
          //if all went well and it's now tuesday, we return the message to the consumer
          return returnMsg; // or null;
      }