docs: private SIBusMessage performReceive(long timeout, SITransaction tran)
        throws SISessionUnavailableException, SISessionDroppedException,
               SIConnectionUnavailableException, SIConnectionDroppedException,
               SIResourceException, SIConnectionLostException, SILimitExceededException,
               SIErrorException,
               SINotAuthorizedException,
               SIIncorrectCallException
     {
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(this, tc, "performReceive", new Object[] { ""+timeout, tran });
  
        if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, ">>>> performReceive invoked with conversation: " + getConversation());
  
        // If we have got into this method but we have a proxy queue or we are read ahead then we
        // should throw this exception to indicate that we do not allow this
        if (proxyQueue != null && !isReadAhead)
        {
           throw new SIIncorrectCallException(
              nls.getFormattedMessage("INCORRECT_RECEIVE_CALL_SICO1061", null, "INCORRECT_RECEIVE_CALL_SICO1061")
           );
        }
  
        if (timeout < -1)
        {
           // The valid timeout values into this method are -1, 0 and any positive integer.
           // Any other values suck.
           SIErrorException e = new SIErrorException(
              nls.getFormattedMessage("INVALID_PROP_SICO8004", new Object[] { ""+timeout }, null)
           );
  
           FFDCFilter.processException(e, CLASS_NAME + ".performReceive",
                                       CommsConstants.CONSUMERSESSIONPROXY_PERFORMRCV_02, this);
  
           throw e;
        }
  
        SIBusMessage mess = null;
  
        // Now perform the exchange to receive the session message on the server
        CommsByteBuffer request = getCommsByteBuffer();
  
        request.putShort(getConnectionObjectID());
        request.putShort(getProxyID());
        request.putSITransaction(tran);
        // Add Timeout (0 would indicate no wait should be performed)
        // -1 inidicates indefinate wait should be performed
        request.putLong(timeout);
  
        // Pass on call to server
        CommsByteBuffer reply = jfapExchange(request,
                                             JFapChannelConstants.SEG_RECEIVE_SESS_MSG,
                                             JFapChannelConstants.PRIORITY_MEDIUM,
                                             true);
  
        try
        {
           short err = reply.getCommandCompletionCode(JFapChannelConstants.SEG_RECEIVE_SESS_MSG_R);
           if (err != CommsConstants.SI_NO_EXCEPTION)
           {
              checkFor_SISessionUnavailableException(reply, err);
              checkFor_SISessionDroppedException(reply, err);
              checkFor_SIConnectionUnavailableException(reply, err);
              checkFor_SIConnectionDroppedException(reply, err);
              checkFor_SIResourceException(reply, err);
              checkFor_SIConnectionLostException(reply, err);
              checkFor_SILimitExceededException(reply, err);
              checkFor_SINotAuthorizedException(reply, err);
              checkFor_SIIncorrectCallException(reply, err);
              checkFor_SIErrorException(reply, err);
              defaultChecker(reply, err);
           }
  
           // If the pending message slices are null then we are simply receiving an entire message
           // as opposed to the message in chunks
           synchronized (pendingMessageSliceLock)
           {
              if (pendingMessageSlices == null)
              {
                 if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Received the entire message");
  
                 // Now build a JsMessage from the returned data. Note that a message length of -1
                 // indicates that no message has been returned and a null value should be returned to the
                 // caller.
                 reply.getShort();                // The connection object Id
                 reply.getShort();                // The consumer session Id
  
                 mess = reply.getMessage(getCommsConnection());
              }
              else
              {
                 if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Received the final slice");
  
                 reply.getShort();                // The connection object Id
                 reply.getShort();                // The consumer session Id
  
                 // Now get the final data slice
                 addMessagePart(reply);
  
                 // Now re-assemble the message
                 try
                 {
                    mess = JsMessageFactory.getInstance().createInboundJsMessage(pendingMessageSlices,
                                                                                 getCommsConnection());
                 }
                 catch (Exception e)
                 {
                    FFDCFilter.processException(e, CLASS_NAME + ".performReceive",
                                                CommsConstants.CONSUMERSESSIONPROXY_PERFORMRCV_02,
                                                this);
  
                    if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Failed to recreate message", e);
  
                    throw new SIResourceException(e);
                 }
              }
  
              if (TraceComponent.isAnyTracingEnabled())
                CommsLightTrace.traceMessageId(tc, "ReceiveMsgTrace", mess);
  
              // Clear the reference to this
              pendingMessageSlices = null;
           }
        }
        finally
        {
           // Ensure the buffer is preserved as it now backs the message we are returning
           if (reply != null) reply.release(false);
        }
  
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(this, tc, "performReceive", mess);
        return mess;
     }