docs: private void internalHandleMessage(MessageItem msg,
                                         TransactionCommon transaction,
                                         SIBUuid8 sourceMEUuid,
                                         JsDestinationAddress inAddress,
                                         MessageProducer sender,
                                         boolean msgFRP)
                      throws SIConnectionLostException, SIRollbackException, SINotPossibleInCurrentConfigurationException,
                      SIIncorrectCallException, SIResourceException
      {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.entry(this, tc, "internalHandleMessage", new Object[] { msg,
                                                                           transaction,
                                                                           sourceMEUuid,
                                                                           inAddress,
                                                                           sender,
                                                                           msgFRP });
  
          if (TraceComponent.isAnyTracingEnabled() && UserTrace.tc_mt.isDebugEnabled())
              traceSend(msg);
  
          boolean lockedDestination = false;
          boolean forcePut = msg.isForcePut();
  
          // This checks the message Reliability against the destination
          // and sets the max storage strategy for temporary destinations
          super.handleMessage(msg);
  
          SIBUuid8 localMEUuid = _messageProcessor.getMessagingEngineUuid();
  
          // Remember if the original user transaction was a real one or not
          msg.setTransacted(!transaction.isAutoCommit());
  
          if (localMEUuid.equals(sourceMEUuid))
          {
              // The message may actually have been produced locally or it may have come
              // from a remote ME and been re-routed to this inputHandler using the
              // routingDestination.
  
              // First, sort out any changes to the message's reverse routing path
              updateReverseRoutingPath(msg);
  
              // First, sort out any changes to the message's reverse routing path
              List<SIDestinationAddress> frp = updateForwardRoutingPath(msg);
  
              //defect 269072: we cannot skip FRP destinations if the next
              //destination is on a foreign bus as we do not know anything
              //about it.
              boolean isPuttingToForeignBus = _destination.isForeignBus();
  
              if (frp != null && !isPuttingToForeignBus) // Correct foreign bus check (aliases?)??
              {
                  handleFRPMessage(msg, transaction, sender, msgFRP);
              }
              else if ((frp == null) &&
                       (_destination.getDestinationType() == DestinationType.SERVICE))
              {
                  //Put the message to the exception destination
                  handleUndeliverableMessage(_destination
                                             , null
                                             , msg
                                             , SIRCConstants.SIRC0034_FORWARD_ROUTING_PATH_ERROR
                                             , new String[] { _destination.getName(),
                                                             _messageProcessor.getMessagingEngineName() },
                                             transaction);
              }
              // Otherwise, we process the message on this destination (or the destination
              // that this destination references - if an alias).
              else
              {
                  // We have not sideways punted the message so need to perform
                  // additional checks now
  
                  //For debug purposes, tell the message which destinations its on
                  if (TraceComponent.isAnyTracingEnabled() && UserTrace.tc_mt.isDebugEnabled())
                  {
                      msg.setDebugName(_destination.getName());
                  }
  
                  // If the message came in from a remote bus then
                  // check whether the userId is authorised to this destination
                  if (msg.isFromRemoteBus() && _messageProcessor.isBusSecure())
                      checkInboundAuthorisation(msg.getMessage());
  
                  // If possible use the sender's cached routing destination (which would
                  // also include any fixed message point).
                  // We can't use it if this message had an FRP already in it as the message
                  // may go elsewhere. This means messages with an embedded FRP cannot be bound to a
                  // single mesage point if the sender requests it
  
                  // Will we need to set a routing destination back into the sender?
                  boolean newSenderRoutingAddr = false;
                  JsDestinationAddress routingAddr = null;
  
                  // Work out if we're already bound to a single ME, or we need to
                  SIBUuid8 fixedME = null;
                  boolean fixToME = false;
                  // If we're in the context of a sender that has specified bindToMessagePoint
                  // and the message doesn't have an FRP embedded into it then we can fix to a single ME
                  if ((sender != null) && sender.fixedMessagePoint() && !msgFRP)
                  {
                      // Fixing on an ME doesn't make sense when sending down a link as we only have the one.
                      // In fact, if you fix to an ME you end up fixing to the target ME (the one at the
                      // other end of the link) which then cancels any attept to workload balance messages
                      // as they come of the link.
                      // TODO: If we ever support multiple links then we need to fix this so that you can
                      //       fix to a single link, rather than the target ME.
                      if (!_destination.isTargetedAtLink())
                          fixToME = true;
                  }
  
                  if (inAddress != null)
                  {
                      // If the address is marked localOnly but we don't already have an
                      // ME in it we'll only use the local message point
                      // if it exists (even if it's currently unavailable).
                      // If we don't have a local one we simply ignore the option
                      // If the destination is foreign it can't possibly have a local
                      // message point.
                      if ((inAddress.getME() == null) && inAddress.isLocalOnly())
                      {
                          if (!_destination.isTargetedAtLink() && _destination.hasLocal())
                          {
                              // Burn this ME's UUID into the address
                              inAddress.setME(_messageProcessor.getMessagingEngineUuid());
                          }
                      }
  
                      // If the address that the sender used has an ME in it, we'll use it
                      if (inAddress.getME() != null)
                      {
                          fixedME = inAddress.getME();
                          fixToME = true;
                      }
                  }
  
                  if (msg.getMessage().isMediated())
                  {
  
                      // The originator of the message (the app)
                      // may have bound the producer to a single message point in the hope of
                      // getting affinity across multiple messages.
  
                      // If this message has only been transformed rather than re-routed 
                      // then we'll have a go at maintaining the affinity on the outbound
                      // queue point. As we don't have the producer's session context we use the existence
                      // of a fixed ME in the routingAddress in the message to indicate that the sender
                      // bound the messages to a single message point.
  
                      // The only routing restriction we can apply reliably (i.e. across ME restarts) is to
                      // send all such messages to the local queue point if it exists (not just available).
                      JsDestinationAddress inRoutingAddress = msg.getMessage().getRoutingDestination();
                      if ((inRoutingAddress != null) && (inRoutingAddress.getME() != null))
                      {
                          if (_destination.hasLocal())
                          {
                              fixedME = _messageProcessor.getMessagingEngineUuid();
                              fixToME = true;
                          }
                      }
                  }
  
                  // If a local sender doesn't already have a routing destination for us or we
                  // can't use it because some *** of an application set an FRP into the message
                  // (which means we can't bind to a single ME if they ask) or the message came in
                  // remotely we need to resolve a routing address.
                  if (msgFRP || (sender == null) || !sender.isRoutingDestinationSet())
                  {
                      // Resolve any required routing destination. This is quite likely to be null
                      // as we only need one for certain reasons (e.g. foreign destination, fixed ME
                      // scoped alias).
                      routingAddr = _destination.getRoutingDestinationAddr(inAddress,
                                                                           fixToME);
  
                      // If we have a fixed ME then set it into the routing address for
                      // anyone else looking at this message.
                      if (fixedME != null)
                      {
                          if ((inAddress == null) || !routingAddr.equals(inAddress))
                          {
                              // If we got this address from the destination handler we need to make a copy of it
                              // before we modify it as this is actually a reference to the cached address on the
                              // destination itself
                              routingAddr = SIMPUtils.createJsDestinationAddress(routingAddr.getDestinationName(),
                                                                                 fixedME,
                                                                                 routingAddr.getBusName());
                          }
                          else
                          {
                              routingAddr = inAddress; // Use the inAddress (which may be 'equal' the destination's but be a different object)
                              routingAddr.setME(fixedME);
                          }
                      }
  
                      // We'll set it back into the sender, if we're allowed.
                      if ((sender != null) && !msgFRP)
                          newSenderRoutingAddr = true;
                  }
                  // If the sender already has a routing destination set (which may be null)
                  // then use it
                  else if ((sender != null) && sender.isRoutingDestinationSet())
                  {
                      routingAddr = sender.getRoutingDestination();
  
                      // Pull out any fixed ME that it has
                      if (routingAddr != null)
                      {
                          fixedME = routingAddr.getME();
                          if (fixedME != null)
                              fixToME = true;
                      }
                  }
  
                  // Now we know if we're fixed to a particular ME or not we can check for
                  // a 'good' OutputHandler. We do this check now, in case we're transacted
                  // and don't try the OutputHandlers until the transaction commits
                  try
                  {
                      checkHandlerAvailable(fixedME);
                  }
                  // This indicates that the queue high limit has been reached
                  catch (SIMPLimitExceededException e)
                  {
                      // No FFDC code needed
  
                      //If we are forcing put then we ignore queue high limits.
                      if (forcePut)
                      {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(tc, "Forcing msg put despite exception :" + e);
                      }
                      // We don't accept messages produced locally when we're full,
                      // we throw an exception back to the app.
                      else if (!msg.isFromRemoteME())
                      {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                          {
                              SibTr.exception(tc, e);
                              SibTr.exit(tc, "internalHandleMessage", "SIMPLimitExceededException");
                          }
                          throw e;
                      }
                      //If it came from another bus then we put the message to the
                      //exception destination.
                      else if (msg.isFromRemoteBus())
                      {
                          if (msg.getReliability().compareTo(Reliability.EXPRESS_NONPERSISTENT) > 0)
                          {
                              // We have already checked at the target stream to see if there is
                              // space for this message either on its destination or on the link's
                              // exception destination.
                              // However, there is a window when either (or both) could have filled
                              // up since the check, perhaps due to local puts.
                              // We rethrow the exception, which will allow the message to be put to
                              // the link's exception destination if possible.
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                                  SibTr.debug(tc, "Message from remote bus rethrow exception: " + e);
                              if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              {
                                  SibTr.exception(tc, e);
                                  SibTr.exit(tc, "internalHandleMessage", "SIMPLimitExceededException");
                              }
                              throw e;
                          }
                          else if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(tc, "Message dropped - it was only best effort");
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "internalHandleMessage");
  
                          return;
                      }
                      // Otherwise, this is a message from a remote ME in this bus. We let
                      // these onto the destination as they've already performed a WLM check
                      // to get here, which mean't we weren't full at the time.
                      else
                      {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                              SibTr.debug(tc, "Allowing remote message on to destination :" + e);
                      }
                  } catch (SIMPNotPossibleInCurrentConfigurationException e)
                  {
                      // No FFDC code needed
                      // This indicates that the queue was put disabled
                      // It doesn't matter whether the message was produced remotely
                      // or locally this is a problem
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                      {
                          SibTr.exception(tc, e);
                          SibTr.exit(tc, "internalHandleMessage", "SIMPNotPossibleInCurrentConfigurationException");
                      }
                      throw e;
                  }
  
                  SIBUuid8 preferredME = null;
                  // If the sender prefers any local ME over others then we'll
                  // give it a go for them
                  if (msg.preferLocal())
                  {
                      if (_destination.hasLocal())
                          preferredME = _messageProcessor.getMessagingEngineUuid();
                  }
  
                  // If message was produced locally and transacted and we have not
                  // decided to force it to be stored now,  we delay the store until
                  // we get a callback at pre-prepare time.
                  if (!(msg.isFromRemoteME())
                      && (msg.isTransacted())
                      && !(msg.isToBeStoredAtSendTime()))
                  {
                      // We need to set any required routing destination into the message
                      // before we register it with the transaction. However, because we're
                      // about to loose the context of the sender (we've no guarantee that
                      // the sender will exist by the time the transaction commits) we need
                      // to make sure that if a fixed message point is still required we
                      // resolve it now.
  
                      // If we've decided we need to fix to a single ME but haven't yet chosen
                      // one, choose it now.
                      if (fixToME && (fixedME == null))
                      {
                          // Choose one of the available output handlers
                          OutputHandler outputHandler =
                                          _destination.choosePtoPOutputHandler(null,
                                                                               preferredME,
                                                                               !msg.isFromRemoteME(),
                                                                               forcePut,
                                                                               null);
  
                          //We can't find a suitable localisation.
                          //Although a queue must have at least one localisation this is
                          //possible if the sender restricted the potential localisations
                          //using a fixed ME or a scoping alias (to an out-of-date set of localisation)
                          //In some cases all we can do is put the message to the exception destination.  In others, we
                          //can throw an exception to the putting application.  From here, we throw an exception
                          //and its up to the calling class to determine how best to handle it
                          if (outputHandler == null)
                          {
                              if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                                  SibTr.exit(
                                             tc,
                                             "internalHandleMessage",
                                             "SIMPNoLocalisationsException");
                              SIMPNoLocalisationsException e = new SIMPNoLocalisationsException(
                                              nls_cwsik.getFormattedMessage(
                                                                            "DELIVERY_ERROR_SIRC_26", // NO_LOCALISATIONS_FOUND_ERROR_CWSIP0032
                                                                            new Object[] { _destination.getName() }, null));
  
                              e.setExceptionReason(SIRCConstants.SIRC0026_NO_LOCALISATIONS_FOUND_ERROR);
                              e.setExceptionInserts(new String[] { _destination.getName() });
                              throw e;
                          }
  
                          // Set the chosen one into the routing destination
                          if ((inAddress == null) || !routingAddr.equals(inAddress))
                          {
                              // If we got this address from the destination handler we need to make a copy of it
                              // before we modify it as this is actually a reference to the cached address on the
                              // destination itself
                              routingAddr = SIMPUtils.createJsDestinationAddress(routingAddr.getDestinationName(),
                                                                                 outputHandler.getTargetMEUuid(),
                                                                                 routingAddr.getBusName());
                          }
                          else
                          {
                              routingAddr = inAddress; // Use the inAddress (which may be 'equal' the destination's but be a different object)
                              routingAddr.setME(outputHandler.getTargetMEUuid());
                          }
                      }
  
                      // Set the routing destination into the message if it's changed
                      if ((routingAddr != null) || (msg.getMessage().getRoutingDestination() != null))
                          msg.getMessage().setRoutingDestination(routingAddr);
  
                      // If necessary, set a new routing destination into the sender.
                      if (newSenderRoutingAddr)
                          sender.setRoutingAddress(routingAddr);
  
                      // Register the message for storing at pre-prepare of the transaction.
                      registerMessage(msg, transaction); //183715.1
                  }
                  else
                  {
                      // If COD reports required, register for the prePrepare callback
                      if (msg.getReportCOD() != null && _destination instanceof BaseDestinationHandler)
                          msg.registerMessageEventListener(MessageEvents.COD_CALLBACK, (BaseDestinationHandler) _destination);
  
                      // Read Lock the destination to prevent the reallocator running on the chosen localisation
                      LockManager reallocationLock = _destination.getReallocationLockManager();
                      reallocationLock.lock();
                      lockedDestination = true;
  
                      try
                      {
                          // 176658.3.5
                          // Now look for the best OutputHander at this time.
                          OutputHandler outputHandler =
                                          _destination.choosePtoPOutputHandler(fixedME,
                                                                               preferredME,
                                                                               (!msg.isFromRemoteME()),
                                                                               forcePut,
                                                                               null);
  
                          //We can't find a suitable localisation.
                          //Although a queue must have at least one localisation this is
                          //possible if the sender restricted the potential localisations
                          //using a fixed ME or a scoping alias (to an out-of-date set of localisation)
                          //In some cases all we can do is put the message to the exception destination.  In others, we
                          //can throw an exception to the putting application.  From here, we throw an exception
                          //and its up to the calling class to determine how best to handle it
                          if (outputHandler == null)
                          {
                              if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                                  SibTr.exit(
                                             tc,
                                             "internalHandleMessage",
                                             "SIMPNoLocalisationsException");
                              SIMPNoLocalisationsException e = new SIMPNoLocalisationsException(
                                              nls_cwsik.getFormattedMessage(
                                                                            "DELIVERY_ERROR_SIRC_26", // NO_LOCALISATIONS_FOUND_ERROR_CWSIP0032
                                                                            new Object[] { _destination.getName() }, null));
  
                              e.setExceptionReason(SIRCConstants.SIRC0026_NO_LOCALISATIONS_FOUND_ERROR);
                              e.setExceptionInserts(new String[] { _destination.getName() });
                              throw e;
                          }
  
                          // If the sender wants all future message to go to the same message
                          // point we fix the message point to be this one for all future requests
                          // (unless it already had it set or this message had an FRP from the message)
                          if (fixToME && (fixedME == null))
                          {
                              // We need to set this chosen ME into the routing destination
                              // as we don't already have it.
                              if ((inAddress == null) || !routingAddr.equals(inAddress))
                              {
                                  // If we got this address from the destination handler we need to make a copy of it
                                  // before we modify it as this is actually a reference to the cached address on the
                                  // destination itself
                                  routingAddr = SIMPUtils.createJsDestinationAddress(routingAddr.getDestinationName(),
                                                                                     outputHandler.getTargetMEUuid(),
                                                                                     routingAddr.getBusName());
                              }
                              else
                              {
                                  routingAddr = inAddress; // Use the inAddress (which may be 'equal' the destination's but be a different object)
                                  routingAddr.setME(outputHandler.getTargetMEUuid());
                              }
                          }
  
                          // Now we set the routing destination into the sender for future use
                          // (with the fixed ME set into it if applicable)
                          if (newSenderRoutingAddr)
                              sender.setRoutingAddress(routingAddr);
  
                          // Now we've resolved any possible fixed ME in the routing destination
                          // we set it into the message (remember, the routing destination is still
                          // most likely to be null).
                          if ((routingAddr != null) || (msg.getMessage().getRoutingDestination() != null))
                              msg.getMessage().setRoutingDestination(routingAddr);
  
                          //Indicate in the message if this was a guess
                          msg.setStreamIsGuess(outputHandler.isWLMGuess());
  
                          boolean stored = false;
  
                          outputHandler.put(msg,
                                            transaction,
                                            null,
                                            stored);
                      } catch (SIMPNoLocalisationsException e)
                      {
                          //No FFDC code needed
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "internalHandleMessage", e);
                          throw e;
                      } catch (SIRollbackException e)
                      {
                          // No FFDC code needed
  
                          SIMPRollbackException ee = new SIMPRollbackException(e.getMessage());
                          ee.setStackTrace(e.getStackTrace());
                          ee.setExceptionReason(SIRCConstants.SIRC0901_INTERNAL_MESSAGING_ERROR);
                          ee.setExceptionInserts(new String[] { "com.ibm.ws.sib.processor.impl.ProducerSessionImpl.handleMessage",
                                                               "1:804:1.323",
                                                               SIMPUtils.getStackTrace(e) });
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "internalHandleMessage", ee);
  
                          throw ee;
                      } catch (SIConnectionLostException e)
                      {
                          // No FFDC code needed
  
                          SIMPConnectionLostException ee = new SIMPConnectionLostException(e.getMessage());
                          ee.setStackTrace(e.getStackTrace());
                          ee.setExceptionReason(SIRCConstants.SIRC0901_INTERNAL_MESSAGING_ERROR);
                          ee.setExceptionInserts(new String[] { "com.ibm.ws.sib.processor.impl.ProducerSessionImpl.handleMessage",
                                                               "1:820:1.323",
                                                               SIMPUtils.getStackTrace(e) });
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "internalHandleMessage", ee);
  
                          throw ee;
                      } catch (SIResourceException e)
                      {
                          // No FFDC code needed
  
                          SIMPResourceException ee = new SIMPResourceException(e);
  
                          ee.setExceptionReason(SIRCConstants.SIRC0901_INTERNAL_MESSAGING_ERROR);
                          ee.setExceptionInserts(new String[] { "com.ibm.ws.sib.processor.impl.ProducerSessionImpl.handleMessage",
                                                               "1:836:1.323",
                                                               SIMPUtils.getStackTrace(e) });
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "internalHandleMessage", ee);
                          throw ee;
                      } catch (RuntimeException e)
                      {
                          // FFDC
                          FFDCFilter.processException(
                                                      e,
                                                      "com.ibm.ws.sib.processor.impl.PtoPInputHandler.internalHandleMessage",
                                                      "1:848:1.323",
                                                      this);
  
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                          {
                              SibTr.exception(tc, e);
                          }
  
                          SIMPErrorException ee = new SIMPErrorException(e);
  
                          ee.setExceptionReason(SIRCConstants.SIRC0901_INTERNAL_MESSAGING_ERROR);
                          ee.setExceptionInserts(new String[] { "com.ibm.ws.sib.processor.impl.ProducerSessionImpl.handleMessage",
                                                               "1:860:1.323",
                                                               SIMPUtils.getStackTrace(e) });
                          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                              SibTr.exit(tc, "internalHandleMessage", ee);
                          throw ee;
                      } finally
                      {
                          if (lockedDestination == true)
                          {
                              // unlock the reallocation lock
                              reallocationLock.unlock();
                              lockedDestination = false;
                          }
                      }
                  }
              }
          }
          else
          {
              // This is a message that has been received from a
              // remote ME. Call remoteToLocal put to add it to the
              // in this case and instead use the one attached to
              // target stream
              // The message will be processed in deliverOrderedMessages when
              // the stream is in order
  
              // We actually ignore the source cellule in this case and
              // instead use the one attached to the message itself.
              try
              {
                  remoteToLocalPut(msg, sourceMEUuid);
              } catch (SIResourceException e)
              {
                  // No FFDC code needed
                  SIMPResourceException ee = new SIMPResourceException(e);
  
                  ee.setExceptionReason(SIRCConstants.SIRC0901_INTERNAL_MESSAGING_ERROR);
                  ee.setExceptionInserts(new String[] { "com.ibm.ws.sib.processor.impl.ProducerSessionImpl.handleMessage",
                                                       "1:900:1.323",
                                                       SIMPUtils.getStackTrace(e) });
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                      SibTr.exit(tc, "internalHandleMessage", ee);
                  throw ee;
              }
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.exit(tc, "internalHandleMessage");
  
          return;
      }