void sendDeletionNotifications(Message notification, Element event, LeafNode leafNode,
            List<PublishedItem> publishedItems) {

        if (publishedItems.isEmpty()) {
            Log.debug("Skip sending delete notifications as the list of deleted items was empty.");
            return;
        }

        Map<List<NodeSubscription>, List<PublishedItem>> itemsBySubs = getItemsBySubscriptions(leafNode, publishedItems);
        Log.trace("Sending delete notification for {} published item(s) to {} subscription(s) in {} batch(es).", publishedItems.size(), itemsBySubs.keySet().stream().flatMap(Collection::stream).collect(Collectors.toSet()).size(), itemsBySubs.size());

        // Send one notification for published items that affect the same subscriptions
        for (final Map.Entry<List<NodeSubscription>, List<PublishedItem>> entry : itemsBySubs.entrySet()) {
            final List<NodeSubscription> nodeSubscriptions = entry.getKey();
            final List<PublishedItem> groupedItems = entry.getValue();
            Log.trace("Preparing delete notification batch for {} item(s) to {} subscription(s).", groupedItems.size(), nodeSubscriptions.size());

            // Add items information
            Element items = event.addElement("items");
            items.addAttribute("node", leafNode.getUniqueIdentifier().getNodeId());
            for (PublishedItem publishedItem : itemsBySubs.get(nodeSubscriptions)) {
                // Add retract information to the event notification
                Element item = items.addElement("retract");
                if (leafNode.isItemRequired()) {
                    item.addAttribute("id", publishedItem.getID());
                }
            }
            // Send the event notification
            sendEventNotification(notification, nodeSubscriptions);
            // Remove the added items information
            event.remove(items);
        }
    }
Sends an event notification to the affiliate for the deleted items. The event
notification may contain one or many published items based on the items included
in the original publication. If the affiliate has many subscriptions and many
items were deleted then the affiliate will get a notification for each set
of items that affected the same subscriptions.

@param notification the message to sent to the subscribers. The message will be completed
       with the items to include in each notification.
@param event the event Element included in the notification message. Passed as an
       optimization to avoid future look ups.
@param leafNode the leaf node where the items where deleted from.
@param publishedItems the list of items that were deleted.
xmppserver/src/main/java/org/jivesoftware/openfire/pubsub/NodeAffiliate.java