docs: private boolean localFanOut(
                                  MessageItem msg,
                                  TransactionCommon tran,
                                  boolean stored)
                      throws
                      SIDiscriminatorSyntaxException,
                      SIResourceException
      {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.entry(
                          tc,
                          "localFanOut",
                          new Object[] { msg, tran, new Boolean(stored) });
  
          boolean notBestEffort = (msg.getReliability().compareTo(Reliability.BEST_EFFORT_NONPERSISTENT)) > 0;
          boolean isTransacted = msg.isTransacted();
  
          //Find matching output handlers    
          MessageProcessorSearchResults searchResults = matchMessage(msg);
  
          String topic = msg.getMessage().getDiscriminator();
  
          //168373.1
          JsMessage jsMsg = msg.getMessage();
  
          // cycle through the Neighbouring ME's
          List matchingPubsubOutputHandlers = searchResults.getPubSubOutputHandlers(topic);
  
          MessageItemReference ref = null;
  
          //Although there may be matching neighbours, some of them
          //may be upstream, and so shouldn't count as matches.
          //Therefore we can only tell if we actually have to initialize msg fields
          //once we start enumerating the output handlers.
          boolean sourceStreamUpdated = false;
          boolean proxyRefStreamUpdated = false;
  
          // Check to see if we have any matching Neighbours
          if (matchingPubsubOutputHandlers != null &&
              matchingPubsubOutputHandlers.size() > 0)
          {
              ArrayList<SIBUuid8> fromTo = null; //see defect 285784: 
              //we should not use array as we might end up with null elements (if there
              //are upstream MEs). The NPE that results causes localPut to bomb-out 
              //before msg is delivered to local ConsumerDispatchers. 
  
              // If we've just registered for the post_commit callback (see above comment)
              // we have nothing else to do here. Otherwise, traverse the list of output handlers. 
              if (notBestEffort || !isTransacted)
              {
                  HashMap allPubSubOutputHandlers = _destination.getAllPubSubOutputHandlers();
                  try
                  {
                      Iterator itr = allPubSubOutputHandlers.values().iterator();
  
                      int i = 0;
                      while (itr.hasNext())
                      {
                          PubSubOutputHandler handler = (PubSubOutputHandler) itr.next();
  
                          //see if this is a topological match 
                          if (handler.okToForward(msg))
                          {
                              //It is only now that we are certain that we have to send the message
                              //to a PSOH - either a msg or a silence. 
                              //Therefore we should now set some message properties
                              //(if we have not already done so)
                              if (!sourceStreamUpdated)
                              {
                                  //set the necessary msg properties EXCEPT the 'bus' field,
                                  //which should not be set before the message is stored.
                                  //The reason is that if the msg is to be stored then we need
                                  //the 'bus' field to be set to the originating bus.
                                  //Stored & best_effort transacted messages have their 
                                  //'bus' field updated after the add
                                  setPropertiesInMessage(jsMsg,
                                                         _destination.getUuid(),
                                                         msg.getProducerConnectionUuid());
  
                                  // This allocates the tick and adds to stream atomically
                                  _sourceStreamManager.addMessage(msg);
  
                                  sourceStreamUpdated = true;
                              }
                              //see if this is a criteria match
                              if (matchingPubsubOutputHandlers.contains(handler))
                              {
                                  if (!proxyRefStreamUpdated)
                                  {
                                      // If this message has a stream (i.e. the message isn't best_effort)
                                      // we create a reference to the message.
                                      // We will then be driven by the commit of this to send the messages
                                      // to the neighbours.
                                      if (notBestEffort)
                                      {
                                          if (!stored)
                                              storeMessage(msg, tran);
                                          stored = true;
                                          ref = addProxyReference(msg, searchResults, tran);
                                      }
                                      // If we are transacted and best_effort we must wait for the transaction to
                                      // be committed before we send the message so we register for an event
                                      // on the transaction before we send the message.
                                      else if (isTransacted)
                                      {
                                          msg.setSearchResults(searchResults);
                                          msg.registerMessageEventListener(MessageEvents.POST_COMMITTED_TRANSACTION, this);
                                      }
                                      // Otherwise, we're non-transacted best_effort and we must send the
                                      // message direct from here, so we build a list of targets from the
                                      // search results.
                                      else
                                      {
                                          fromTo = new ArrayList<SIBUuid8>(matchingPubsubOutputHandlers.size()); //We use the 
                                          //match list size as an initial capacity as it is probably 
                                          //quite a good guess.
                                      }
                                      proxyRefStreamUpdated = true;
                                  }
  
                                  // Put the message to the Neighbour.
                                  stored = handler.put(msg, tran, this, stored);
  
                                  if (!notBestEffort)
                                  {
                                      //i.e. we are best effort non transacted
                                      //Update the bus field - defect 260440: 
                                      //we should set the 'bus' in the jsMsg here because
                                      //the message is not going to be stored. 
                                      jsMsg.setBus(_messageProcessor.getMessagingEngineBus());
  
                                      //add a target cellule to the array for sending
                                      //or send the message directly from the outputHandler
                                      //if this is a Link 
                                      if (handler.isLink())
                                      {
                                          // If the output handler is a link, only forward it if it isn't to
                                          // the bus it may have just come from.
                                          handler.sendLinkMessage(msg, false);
                                      }
                                      else
                                      {
                                          // Add this handler to th target list
                                          SIBUuid8 targetCellule = handler.getTargetMEUuid();
                                          fromTo.add(targetCellule); //see defect 285784
                                          i++;
  
                                          // trace the fact we're about to transmit the message
                                          if (TraceComponent.isAnyTracingEnabled() && UserTrace.tc_mt.isDebugEnabled())
                                              UserTrace.traceOutboundSend(jsMsg,
                                                                          handler.getTargetMEUuid(),
                                                                          _destination.getName(),
                                                                          _destination.isForeignBus() || _destination.isLink(),
                                                                          _destination.isMQLink(),
                                                                          _destination.isTemporary());
                                      }
                                  }
                              }
                              else if (notBestEffort)
                              {
                                  // There is no criteria match, so we put completed into the stream.
                                  // Set "create" to true in case this is the first time
                                  // this stream has seen a tick.
                                  handler.putSilence(msg);
                              }
                          }//end topological match
                           // defect 260440: 
                           // 601 used to now remove this OH from 
                           // the set of matching outputhandlers, but it is cheaper
                           // instead to merely repeat the 'okToForward' check later on
                           //  else
                           //  {
                           //    if(matchingPubsubOutputHandlers.contains(handler))
                           //    {
                           //      matchingPubsubOutputHandlers.remove(handler);
                           //    }              
                           //  }
                      }//end while
  
                      // If we've built a list of targets we must want to send them
                      // directly from here (we're non-transacted best effort)
                      if (i > 0)
                      {
                          //Now that we have a list of fromTo pairs we can obtain an array representation 
                          //see defect 285784
                          SIBUuid8[] fromToArray =
                                          fromTo.toArray(new SIBUuid8[fromTo.size()]);
                          _mpio.sendDownTree(fromToArray, //the list of source target pairs
                                             msg.getPriority(), //priority
                                             jsMsg); //the JsMessage
                      }
                  } finally
                  {
                      // unlock as the getAllPubSubOutputHandlers locks it.
                      _destination.unlockPubsubOutputHandlers();
                  }
              }
              else
              {
                  //we are best effort and transacted
                  //We need to scan the loop of PSOHs and make sure at least one is okToForward
                  Iterator itr = _destination.getAllPubSubOutputHandlers().values().iterator();
                  try
                  {
                      while (itr.hasNext())
                      {
                          PubSubOutputHandler handler = (PubSubOutputHandler) itr.next();
                          //see if this is a topological match 
                          if (handler.okToForward(msg) && matchingPubsubOutputHandlers.contains(handler))
                          {
                              msg.setSearchResults(searchResults);
                              msg.registerMessageEventListener(MessageEvents.POST_COMMITTED_TRANSACTION, this);
                              break;
                          }
                      }//end while
                  } finally
                  {
                      // unlock as the getAllPubSubOutputHandlers locks it.
                      _destination.unlockPubsubOutputHandlers();
                  }
              }
          }
          else
          {
              //Set a unique id in the message if explicitly told to or
              //if one has not already been set
              if (msg.getRequiresNewId() || jsMsg.getSystemMessageId() == null)
              {
                  jsMsg.setSystemMessageSourceUuid(_messageProcessor.getMessagingEngineUuid());
                  jsMsg.setSystemMessageValue(_messageProcessor.nextTick());
                  msg.setRequiresNewId(false);
              }
          }
  
          stored = deliverToConsumerDispatchers(searchResults, msg, tran, stored);
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.exit(tc, "localFanOut", new Boolean(stored));
  
          return stored;
      }