log.info("router returned delivery " + del);
   protected void deliverInternal(boolean handle) throws Throwable   {      try      {         // The iterator is used to iterate through the refs in the channel in the case that they         // don't match the selectors of any receivers.         ListIterator iter = null;                  MessageReference ref = null;                  while (true)         {                       synchronized (refLock)            {                             if (iter == null)               {                  ref = (MessageReference) messageRefs.peekFirst();               }               else               {                  if (iter.hasNext())                  {                                             ref = (MessageReference)iter.next();                  }                   else                  {                     ref = null;                  }               }            }            if (ref != null)            {               // Check if message is expired (we also do this on the client               // side)               // If so ack it from the channel               if (ref.isExpired())               {                  if (trace) { log.trace("Message reference: " + ref + " has expired"); }                  // remove and acknowledge it                  if (iter == null)                  {                     removeFirstInMemory();                  }                  else                  {                     iter.remove();                  }                  Delivery delivery = new SimpleDelivery(this, ref, true);                  acknowledgeInternal(delivery, null, true, false);               }               else               {                  // Reference is not expired                  // Attempt to push the ref to a receiver, so increment the delivery count                  ref.incrementDeliveryCount();                  Delivery del = router.handle(this, ref, null);                  if (del == null)                  {                     // No receiver, broken receiver or full receiver so we stop delivering; also                     // we need to decrement the delivery count, as no real delivery has been                     // actually performed                     if (trace) { log.trace(this + ": no delivery returned for message" + ref + " so no receiver got the message. Delivery is now complete"); }                     ref.decrementDeliveryCount();                     receiversReady = false;                     return;                  }                  else if (!del.isSelectorAccepted())                  {                     // No receiver accepted the message because no selectors matched, so we create                     // an iterator (if we haven't already created it) to iterate through the refs                     // in the channel. No delivery was really performed, so we decrement the                     // delivery count                     ref.decrementDeliveryCount();                     // TODO Note that this is only a partial solution since if there are messages                     // paged to storage it won't try those - i.e. it will only iterate through                     // those refs in memory. Dealing with refs in storage is somewhat tricky since                     // we can't just load them and iterate through them since we might run out of                     // memory, so we will need to load individual refs from storage given the                     // selector expressions. Secondly we should also introduce some in memory                     // indexes here to prevent having to iterate through all the refs every time.                     // Having said all that, having consumers on a queue that don't match many                     // messages is an antipattern and should be avoided by the user.                     if (iter == null)                     {                        iter = messageRefs.iterator();                     }                                       }                  else                  {                     if (trace) { log.trace(this + ": " + del + " returned for message:" + ref); }                                          // Receiver accepted the reference                     // We must synchronize here to cope with another race condition where message                     // is cancelled/acked in flight while the following few actions are being                     // performed. e.g. delivery could be cancelled acked after being removed from                     // state but before delivery being added (observed).                     synchronized (del)                     {                        if (trace) { log.trace(this + " incrementing delivery count for " + del); }                        // FIXME - It's actually possible the delivery could be                        // cancelled before it reaches                        // here, in which case we wouldn't get a delivery but we                        // still need to increment the                        // delivery count                        // All the problems related to these race conditions and                        // fiddly edge cases will disappear                        // once we do                        // http://jira.jboss.com/jira/browse/JBMESSAGING-355                        // This will make life a lot easier                        del.getReference().incrementDeliveryCount();                                            if (!del.isCancelled())                        {                           if (iter == null)                           {                              removeFirstInMemory();                           }                           else                           {                              iter.remove();                                                           }                           // delivered                           if (!del.isDone())                           {                              // Add the delivery to state                              synchronized (deliveryLock)                              {                                 deliveries.add(del);                              }                           }                        }                     }                  }               }            }            else            {               // No more refs in channel or only ones that don't match any selectors               if (trace) { log.trace(this + " no more refs to deliver "); }               break;            }         }      }      catch (Throwable t)      {         log.error(this + " Failed to deliver", t);      }   }