docs: private DestinationHandler handleFRPMessage(MessageItem msg,
                                                  TransactionCommon tran,
                                                  MessageProducer sender,
                                                  boolean msgFRP)
  
                      throws SINotAuthorizedException,
                      SIMPNotPossibleInCurrentConfigurationException,
                      SIResourceException
      {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.entry(tc, "handleFRPMessage", new Object[] { msg, tran, sender, Boolean.valueOf(msgFRP) });
  
          List<SIDestinationAddress> frp = msg.getMessage().getForwardRoutingPath();
  
          // Walk down the FRP until we come to a destination that the message needs
          // to go to.
          // e.g. it's the end of the list, it's a topicspace or it's in a foreign bus
          JsDestinationAddress head = null;
          DestinationHandler frpDestination = null;
          DestinationHandler previousDestination = _destination;
          do
          {
              // Pop off first element of FRP
              head = (JsDestinationAddress) frp.get(0);
  
              String name = head.getDestinationName();
              String busName = head.getBusName();
  
              //Get the named destination from the destination manager
              try
              {
                  frpDestination =
                                  _messageProcessor.getDestinationManager().
                                                  getDestination(name, busName, false);
  
                  // If security is enabled, then we need to check authority to access
                  // the next destination
                  if (_messageProcessor.isBusSecure())
                  {
                      // Will drive the form of sib.security checkDestinationAccess() that
                      // takes a JsMessage
                      JsMessage jsMsg = msg.getMessage();
                      String discriminator = jsMsg.getDiscriminator();
                      SecurityContext secContext = new SecurityContext(jsMsg,
                                      null, // alt user
                                      discriminator,
                                      _messageProcessor.getAuthorisationUtils());
                      checkDestinationAccess(frpDestination,
                                             secContext);
                  }
  
                  previousDestination = frpDestination;
  
                  frp.remove(0);
              } catch (SIException e)
              {
                  // No FFDC code Needed
  
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                      SibTr.exception(tc, e);
  
                  // Need to throw NotAuthorized exceptions back to the caller.
                  if (e instanceof SINotAuthorizedException)
                  {
                      // Write an audit record if access is denied
                      SibTr.audit(tc, nls_cwsik.getFormattedMessage(
                                                                    "DELIVERY_ERROR_SIRC_18", // USER_NOT_AUTH_SEND_ERROR_CWSIP0308
                                                                    new Object[] { name,
                                                                                  msg.getMessage().getSecurityUserid() },
                                                                    null));
  
                      // Thrown if user denied access to destination
                      SIMPNotAuthorizedException ex =
                                      new SIMPNotAuthorizedException(e.getMessage());
  
                      ex.setExceptionReason(SIRCConstants.SIRC0020_USER_NOT_AUTH_SEND_ERROR);
                      ex.setExceptionInserts(new String[] { name,
                                                           msg.getMessage().getSecurityUserid() });
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                          SibTr.exit(tc, "handleFRPMessage", ex);
                      throw ex;
                  }
  
                  ExceptionDestinationHandlerImpl excDest = new ExceptionDestinationHandlerImpl(previousDestination);
  
                  final UndeliverableReturnCode rc =
                                  excDest.handleUndeliverableMessage(msg,
                                                                     tran,
                                                                     SIRCConstants.SIRC0037_INVALID_ROUTING_PATH_ERROR,
                                                                     new String[] { name,
                                                                                   _messageProcessor.getMessagingEngineName(),
                                                                                   previousDestination.getName(),
                                                                                   SIMPUtils.getStackTrace(e)
                                                                     });
  
                  if (rc == UndeliverableReturnCode.ERROR || rc == UndeliverableReturnCode.BLOCK)
                  {
                      SIMPNotPossibleInCurrentConfigurationException ee = new SIMPNotPossibleInCurrentConfigurationException(
                                      nls_cwsik.getFormattedMessage(
                                                                    "DELIVERY_ERROR_SIRC_23", // EXCEPTION_DESTINATION_ERROR_CWSIP0296
                                                                    new Object[] { name, rc, SIMPUtils.getStackTrace(e), _destination.getName() },
                                                                    null),
                                      e);
  
                      ee.setExceptionReason(SIRCConstants.SIRC0023_EXCEPTION_DESTINATION_ERROR);
                      ee.setExceptionInserts(new String[] { name, rc.toString(), SIMPUtils.getStackTrace(e), _destination.getName() });
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                          SibTr.exit(tc, "handleFRPMessage", ee);
                      throw ee;
                  }
  
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                      SibTr.exit(tc, "handleFRPMessage");
                  // Indicate message was delivered to exception destination
                  return null;
              }
  
          } // bypass the destination if its a queue (If the destination
            // is foreign we cannot tell if there is a medition or not, so we err on the side of
            // caution and send it there anyway)
          while ((!previousDestination.isPubSub() && // and it is not PubSub
                  !frp.isEmpty() && // and there is more FRP to process
          !(previousDestination.isForeign() || previousDestination.isForeignBus()))); // and it is not foreign
  
          // Set the remainder of the FRP back into the message
          msg.getMessage().setForwardRoutingPath(frp);
  
          // Get the InputHandler for the chosen destination 
          ProducerInputHandler handler = null;
          if (frpDestination != null)
          {
              ProtocolType type = ProtocolType.UNICASTINPUT;
              if (frpDestination.isPubSub())
                  type = ProtocolType.PUBSUBINPUT;
              handler = (ProducerInputHandler) frpDestination.getInputHandler(type,
                                                                              _messageProcessor.getMessagingEngineUuid(),
                                                                              null);
          }
  
          // If handler is null, the message went to the exception destination.
          // Otherwise we have a new InputHandler for the next interesting destination
          // in the FRP. Let it process the message.
          if (handler != null)
          {
              try
              {
                  // Do some cleanup of the message to make it look like new 
                  JsMessage jsMsg = msg.getMessage();
  
                  // Defect 496906: Set the outAddress to "head" - the JsDestinationAddress of the
                  // frpDestination we are working with. This variable is used as a base from which
                  // to generate the routing address which will be set into the message.
                  JsDestinationAddress outAddress = head;
                  // Reset the redelivery count
                  jsMsg.setRedeliveredCount(0);
  
                  // If the FRP destination is either an alias or is foreign, then update
                  // the RFH2 flag.
                  if (frpDestination.isAlias() ||
                      frpDestination.isForeign() ||
                      frpDestination.isForeignBus())
                  {
                      ProducerSessionImpl.setRFH2Allowed(jsMsg, frpDestination);
                  }
  
                  msg.incrementRedirectCount();
  
                  // Generate error if max frp depth is exceeded
                  if (msg.getRedirectCount() > _messageProcessor.getCustomProperties().get_max_frp_depth())
                  {
                      SibTr.register(PtoPInputHandler.class,
                                     SIMPConstants.MP_TRACE_GROUP,
                                     SIMPConstants.CWSIK_RESOURCE_BUNDLE);
  
                      SibTr.error(tc, "DELIVERY_ERROR_SIRC_43",
                                  new Integer(msg.getRedirectCount()));
  
                      SibTr.register(PtoPInputHandler.class,
                                     SIMPConstants.MP_TRACE_GROUP,
                                     SIMPConstants.RESOURCE_BUNDLE);
  
                      //Put the message to the exception destination
                      handleUndeliverableMessage(frpDestination
                                                 , null // LinkHandler
                                                 , msg
                                                 , SIRCConstants.SIRC0043_MAX_FRP_DEPTH_EXCEEDED
                                                 , new String[] { frpDestination.getName() },
                                                 tran);
                  }
                  // We haven't hit the loop limit so lets pass the message onto the
                  // next InputHandler
                  else
                  {
                      handler.handleProducerMessage(msg,
                                                    tran,
                                                    outAddress,
                                                    null,
                                                    msgFRP);
                  }
              } catch (SIMPNoLocalisationsException e)
              {
                  // No FFDC code needed
  
                  // 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)
  
                  //Put the message to the exception destination
                  handleUndeliverableMessage(frpDestination
                                             , null // LinkHandler
                                             , msg
                                             , SIRCConstants.SIRC0026_NO_LOCALISATIONS_FOUND_ERROR
                                             , new String[] { frpDestination.getName() },
                                             tran);
              } catch (Exception e)
              {
                  //defect 259323
                  //due to an unexpected error we cannot send this message along the
                  //FRP. The best we can do is send the message to the exception destination
                  //and ffdc/trace this event
                  FFDCFilter.processException(
                                              e,
                                              "com.ibm.ws.sib.processor.impl.PtoPInputHandler.handleFRPMessage",
                                              "1:2072:1.323",
                                              this);
  
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                  {
                      SibTr.debug(tc, "FRP message being put to exception destination",
                                  new Object[] { msg, e });
                  }
                  handleUndeliverableMessage(frpDestination
                                             , null // LinkHandler
                                             , msg
                                             , SIRCConstants.SIRC0001_DELIVERY_ERROR
                                             , new String[] { frpDestination.getName() },
                                             tran);
              }
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.exit(tc, "handleFRPMessage");
  
          return frpDestination;
      }