Move offline stanza receiver to the default stanza broker
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java b/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java
index c1172ff..7993ea4 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java
@@ -39,21 +39,20 @@
 import org.apache.vysper.xmpp.authentication.AccountManagement;
 import org.apache.vysper.xmpp.delivery.OfflineStanzaReceiver;
 import org.apache.vysper.xmpp.delivery.StanzaRelay;
-import org.apache.vysper.xmpp.delivery.failure.DeliveredToOfflineReceiverException;
 import org.apache.vysper.xmpp.delivery.failure.DeliveryException;
 import org.apache.vysper.xmpp.delivery.failure.DeliveryFailureStrategy;
 import org.apache.vysper.xmpp.delivery.failure.LocalRecipientOfflineException;
 import org.apache.vysper.xmpp.delivery.failure.NoSuchLocalUserException;
 import org.apache.vysper.xmpp.delivery.failure.ServiceNotAvailableException;
-import org.apache.vysper.xmpp.modules.extension.xep0160_offline_storage.OfflineStorageProvider;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.protocol.StanzaHandlerExecutorFactory;
 import org.apache.vysper.xmpp.protocol.StanzaProcessor;
 import org.apache.vysper.xmpp.protocol.worker.InboundStanzaProtocolWorker;
+import org.apache.vysper.xmpp.protocol.worker.UnconnectedProtocolWorker;
+import org.apache.vysper.xmpp.server.InternalSessionContext;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.SessionState;
-import org.apache.vysper.xmpp.server.InternalSessionContext;
 import org.apache.vysper.xmpp.server.components.ComponentRegistry;
 import org.apache.vysper.xmpp.server.resources.ManagedThreadPool;
 import org.apache.vysper.xmpp.server.resources.ManagedThreadPoolUtil;
@@ -77,7 +76,7 @@
  */
 public class DeliveringInternalInboundStanzaRelay implements StanzaRelay, ManagedThreadPool {
 
-    final Logger logger = LoggerFactory.getLogger(DeliveringInternalInboundStanzaRelay.class);
+    private static final Logger LOG = LoggerFactory.getLogger(DeliveringInternalInboundStanzaRelay.class);
 
     private static class RejectedDeliveryHandler implements RejectedExecutionHandler {
 
@@ -97,6 +96,8 @@
 
     private InboundStanzaProtocolWorker inboundStanzaProtocolWorker;
 
+    private UnconnectedProtocolWorker unconnectedProtocolWorker;
+
     private final ComponentRegistry componentRegistry;
 
     private static final Integer PRIO_THRESHOLD = 0;
@@ -107,8 +108,6 @@
 
     protected AccountManagement accountVerification;
 
-    protected OfflineStanzaReceiver offlineStanzaReceiver = null;
-
     protected Entity serverEntity;
 
     protected ServerRuntimeContext serverRuntimeContext = null;
@@ -120,25 +119,23 @@
     protected long lastDumpTimestamp = 0;
 
     public DeliveringInternalInboundStanzaRelay(Entity serverEntity, InternalResourceRegistry resourceRegistry,
-                                                StorageProviderRegistry storageProviderRegistry, ComponentRegistry componentRegistry) {
+            StorageProviderRegistry storageProviderRegistry, ComponentRegistry componentRegistry) {
         this(serverEntity, resourceRegistry, componentRegistry,
-                storageProviderRegistry.retrieve(AccountManagement.class),
-                storageProviderRegistry.retrieve(OfflineStorageProvider.class));
+                storageProviderRegistry.retrieve(AccountManagement.class)
+        );
     }
 
     public DeliveringInternalInboundStanzaRelay(Entity serverEntity, InternalResourceRegistry resourceRegistry,
-                                                ComponentRegistry componentRegistry, AccountManagement accountVerification,
-                                                OfflineStanzaReceiver offlineStanzaReceiver) {
+                                                ComponentRegistry componentRegistry, AccountManagement accountVerification) {
         this.serverEntity = serverEntity;
         this.resourceRegistry = resourceRegistry;
         this.componentRegistry = requireNonNull(componentRegistry);
         this.accountVerification = accountVerification;
-        this.offlineStanzaReceiver = offlineStanzaReceiver;
         int coreThreadCount = 10;
         int maxThreadCount = 20;
         int threadTimeoutSeconds = 2 * 60;
         this.executor = new ThreadPoolExecutor(coreThreadCount, maxThreadCount, threadTimeoutSeconds, TimeUnit.SECONDS,
-                new LinkedBlockingQueue<Runnable>(), new RejectedDeliveryHandler(this, logger));
+                new LinkedBlockingQueue<>(), new RejectedDeliveryHandler(this, LOG));
     }
 
     /* package */ DeliveringInternalInboundStanzaRelay(ExecutorService executor) {
@@ -152,6 +149,7 @@
 
     public void setStanzaHandlerExecutorFactory(StanzaHandlerExecutorFactory stanzaHandlerExecutorFactory) {
         this.inboundStanzaProtocolWorker = new InboundStanzaProtocolWorker(stanzaHandlerExecutorFactory);
+        this.unconnectedProtocolWorker = new UnconnectedProtocolWorker(stanzaHandlerExecutorFactory);
     }
 
     public final void setLogStorageProvider(final LogStorageProvider logStorageProvider) {
@@ -194,7 +192,7 @@
     }
 
     public void relay(InternalSessionContext sessionContext, Entity receiver, Stanza stanza,
-                      DeliveryFailureStrategy deliveryFailureStrategy) throws DeliveryException {
+            DeliveryFailureStrategy deliveryFailureStrategy) throws DeliveryException {
         if (!isRelaying()) {
             throw new ServiceNotAvailableException("internal inbound relay is not relaying");
         }
@@ -225,7 +223,7 @@
         protected final UnmodifyableSessionStateHolder sessionStateHolder = new UnmodifyableSessionStateHolder();
 
         Relay(InternalSessionContext sessionContext, Entity receiver, Stanza stanza,
-              DeliveryFailureStrategy deliveryFailureStrategy) {
+                DeliveryFailureStrategy deliveryFailureStrategy) {
             this.sessionContext = sessionContext;
             this.receiver = receiver;
             this.stanza = stanza;
@@ -340,7 +338,7 @@
                 return relayToBestSessions(false);
             }
 
-            return relayNotPossible();
+            return new RelayResult(new ServiceNotAvailableException());
         }
 
         @SpecCompliant(spec = "draft-ietf-xmpp-3921bis-00", section = "8.2.", status = SpecCompliant.ComplianceStatus.IN_PROGRESS, coverage = SpecCompliant.ComplianceCoverage.COMPLETE)
@@ -375,19 +373,21 @@
             return new RelayResult(new ServiceNotAvailableException());
         }
 
-        private RelayResult relayNotPossible() {
+        private RelayResult relayToOfflineReceiver() {
             if (!accountVerification.verifyAccountExists(receiver)) {
-                logger.warn("cannot relay to unexisting receiver {} stanza {}", receiver.getFullQualifiedName(),
-                        stanza.toString());
+                LOG.warn("cannot relay to unexisting receiver {} stanza {}", receiver.getFullQualifiedName(),
+                        stanza);
                 return new RelayResult(new NoSuchLocalUserException());
-            } else if (offlineStanzaReceiver != null) {
-                offlineStanzaReceiver.receive(stanza);
-                return new RelayResult(new DeliveredToOfflineReceiverException());
-            } else {
-                logger.warn("cannot relay to offline receiver {} stanza {}", receiver.getFullQualifiedName(),
-                        stanza.toString());
+            }
+
+            StanzaHandler stanzaHandler = serverRuntimeContext.getHandler(stanza);
+            if (stanzaHandler.isSessionRequired()) {
+                LOG.warn("cannot relay to offline receiver {} stanza {}", receiver.getFullQualifiedName(), stanza);
                 return new RelayResult(new LocalRecipientOfflineException());
             }
+            unconnectedProtocolWorker.processStanza(serverRuntimeContext, null, sessionStateHolder, stanza,
+                    stanzaHandler);
+            return new RelayResult().setProcessed();
         }
 
         protected RelayResult relayToBestSessions(final boolean fallbackToBareJIDAllowed) {
@@ -401,7 +401,7 @@
             }
 
             if (receivingSessions.size() == 0) {
-                return relayNotPossible();
+                return relayToOfflineReceiver();
             }
 
             RelayResult relayResult = new RelayResult();
@@ -412,8 +412,8 @@
                 }
                 try {
                     StanzaHandler stanzaHandler = receivingSession.getServerRuntimeContext().getHandler(stanza);
-                    inboundStanzaProtocolWorker.processStanza(serverRuntimeContext, receivingSession, sessionStateHolder, stanza,
-                            stanzaHandler);
+                    inboundStanzaProtocolWorker.processStanza(serverRuntimeContext, receivingSession,
+                            sessionStateHolder, stanza, stanzaHandler);
                 } catch (Exception e) {
                     relayResult.addProcessingError(new DeliveryException("no relay to non-authenticated sessions"));
                     continue;
@@ -434,11 +434,11 @@
                     : resourceRegistry.getSessions(receiver, prioThreshold);
 
             if (receivingSessions.size() == 0) {
-                return relayNotPossible();
+                return relayToOfflineReceiver();
             }
 
             if (receivingSessions.size() > 1) {
-                logger.warn("multiplexing: {} sessions will be processing {} ", receivingSessions.size(), stanza);
+                LOG.warn("multiplexing: {} sessions will be processing {} ", receivingSessions.size(), stanza);
             }
 
             RelayResult relayResult = new RelayResult();
@@ -450,8 +450,8 @@
                 }
                 try {
                     StanzaHandler stanzaHandler = sessionContext.getServerRuntimeContext().getHandler(stanza);
-                    inboundStanzaProtocolWorker.processStanza(serverRuntimeContext, sessionContext, sessionStateHolder, stanza,
-                            stanzaHandler);
+                    inboundStanzaProtocolWorker.processStanza(serverRuntimeContext, sessionContext, sessionStateHolder,
+                            stanza, stanzaHandler);
                 } catch (Exception e) {
                     relayResult.addProcessingError(new DeliveryException(e));
                 }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/base/handler/MessageHandler.java b/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/base/handler/MessageHandler.java
index 75c127f..5f87f08 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/base/handler/MessageHandler.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/base/handler/MessageHandler.java
@@ -54,6 +54,11 @@
     }
 
     @Override
+    public boolean isSessionRequired() {
+        return false;
+    }
+
+    @Override
     protected List<Stanza> executeCore(XMPPCoreStanza stanza, ServerRuntimeContext serverRuntimeContext,
             boolean isOutboundStanza, SessionContext sessionContext, StanzaBroker stanzaBroker) {
 
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceHandler.java b/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceHandler.java
index a3fcfd5..49e2541 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceHandler.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceHandler.java
@@ -55,6 +55,11 @@
     }
 
     @Override
+    public boolean isSessionRequired() {
+        return false;
+    }
+
+    @Override
     protected List<Stanza> executeCore(XMPPCoreStanza stanza, ServerRuntimeContext serverRuntimeContext,
                                        boolean isOutboundStanza, SessionContext sessionContext, StanzaBroker stanzaBroker) {
         PresenceStanza presenceStanza = (PresenceStanza) stanza;
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaBroker.java b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/DefaultStanzaBroker.java
similarity index 66%
rename from server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaBroker.java
rename to server/core/src/main/java/org/apache/vysper/xmpp/protocol/DefaultStanzaBroker.java
index f52c2f6..4c3b9ba 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaBroker.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/DefaultStanzaBroker.java
@@ -22,6 +22,7 @@
 import static java.util.Objects.requireNonNull;
 
 import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.delivery.OfflineStanzaReceiver;
 import org.apache.vysper.xmpp.delivery.StanzaRelay;
 import org.apache.vysper.xmpp.delivery.failure.DeliveryException;
 import org.apache.vysper.xmpp.delivery.failure.DeliveryFailureStrategy;
@@ -31,15 +32,23 @@
 /**
  * @author Réda Housni Alaoui
  */
-public class SimpleStanzaBroker implements StanzaBroker {
+public class DefaultStanzaBroker implements StanzaBroker {
 
     private final StanzaRelay stanzaRelay;
 
     private final InternalSessionContext sessionContext;
 
-    public SimpleStanzaBroker(StanzaRelay stanzaRelay, InternalSessionContext sessionContext) {
+    private final OfflineStanzaReceiver offlineStanzaReceiver;
+
+    public DefaultStanzaBroker(StanzaRelay stanzaRelay, InternalSessionContext sessionContext,
+            OfflineStanzaReceiver offlineStanzaReceiver) {
         this.stanzaRelay = requireNonNull(stanzaRelay);
         this.sessionContext = sessionContext;
+        this.offlineStanzaReceiver = offlineStanzaReceiver;
+    }
+    
+    public DefaultStanzaBroker(StanzaRelay stanzaRelay, InternalSessionContext sessionContext){
+        this(stanzaRelay, sessionContext, null);
     }
 
     @Override
@@ -56,11 +65,14 @@
         if (stanza == null) {
             return;
         }
-        if (sessionContext == null) {
-            // TODO Move offline storage here?
+        if (sessionContext != null) {
+            sessionContext.getResponseWriter().write(stanza);
             return;
         }
-        sessionContext.getResponseWriter().write(stanza);
+        if (offlineStanzaReceiver == null) {
+            return;
+        }
+        offlineStanzaReceiver.receive(stanza);
     }
 
     @Override
@@ -72,18 +84,23 @@
             return false;
         }
 
-        SimpleStanzaBroker that = (SimpleStanzaBroker) o;
+        DefaultStanzaBroker that = (DefaultStanzaBroker) o;
 
         if (!stanzaRelay.equals(that.stanzaRelay)) {
             return false;
         }
-        return sessionContext != null ? sessionContext.equals(that.sessionContext) : that.sessionContext == null;
+        if (sessionContext != null ? !sessionContext.equals(that.sessionContext) : that.sessionContext != null) {
+            return false;
+        }
+        return offlineStanzaReceiver != null ? offlineStanzaReceiver.equals(that.offlineStanzaReceiver)
+                : that.offlineStanzaReceiver == null;
     }
 
     @Override
     public int hashCode() {
         int result = stanzaRelay.hashCode();
         result = 31 * result + (sessionContext != null ? sessionContext.hashCode() : 0);
+        result = 31 * result + (offlineStanzaReceiver != null ? offlineStanzaReceiver.hashCode() : 0);
         return result;
     }
 }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerExecutor.java b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerExecutor.java
index 25e28f8..3ceb0af 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerExecutor.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerExecutor.java
@@ -21,6 +21,7 @@
 
 import static java.util.Objects.requireNonNull;
 
+import org.apache.vysper.xmpp.delivery.OfflineStanzaReceiver;
 import org.apache.vysper.xmpp.delivery.StanzaRelay;
 import org.apache.vysper.xmpp.server.InternalSessionContext;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
@@ -35,9 +36,13 @@
 
     private final StanzaHandler stanzaHandler;
 
-    public SimpleStanzaHandlerExecutor(StanzaRelay stanzaRelay, StanzaHandler stanzaHandler) {
+    private final OfflineStanzaReceiver offlineStanzaReceiver;
+
+    public SimpleStanzaHandlerExecutor(StanzaRelay stanzaRelay, StanzaHandler stanzaHandler,
+            OfflineStanzaReceiver offlineStanzaReceiver) {
         this.stanzaRelay = requireNonNull(stanzaRelay);
         this.stanzaHandler = requireNonNull(stanzaHandler);
+        this.offlineStanzaReceiver = offlineStanzaReceiver;
     }
 
     @Override
@@ -47,7 +52,7 @@
                 serverRuntimeContext.getStanzaHandlerInterceptors());
 
         interceptorChain.intercept(stanza, serverRuntimeContext, isOutboundStanza, sessionContext, sessionStateHolder,
-                new SimpleStanzaBroker(stanzaRelay, sessionContext));
+                new DefaultStanzaBroker(stanzaRelay, sessionContext, offlineStanzaReceiver));
     }
 
 }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerExecutorFactory.java b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerExecutorFactory.java
index efcf05e..b8c0e84 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerExecutorFactory.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerExecutorFactory.java
@@ -21,6 +21,7 @@
 
 import static java.util.Objects.requireNonNull;
 
+import org.apache.vysper.xmpp.delivery.OfflineStanzaReceiver;
 import org.apache.vysper.xmpp.delivery.StanzaRelay;
 
 /**
@@ -30,13 +31,20 @@
 
     private final StanzaRelay stanzaRelay;
 
-    public SimpleStanzaHandlerExecutorFactory(StanzaRelay stanzaRelay) {
+    private final OfflineStanzaReceiver offlineStanzaReceiver;
+
+    public SimpleStanzaHandlerExecutorFactory(StanzaRelay stanzaRelay, OfflineStanzaReceiver offlineStanzaReceiver) {
         this.stanzaRelay = requireNonNull(stanzaRelay);
+        this.offlineStanzaReceiver = offlineStanzaReceiver;
+    }
+    
+    public SimpleStanzaHandlerExecutorFactory(StanzaRelay stanzaRelay){
+        this(stanzaRelay, null);
     }
 
     @Override
     public StanzaHandlerExecutor build(StanzaHandler stanzaHandler) {
-        return new SimpleStanzaHandlerExecutor(stanzaRelay, stanzaHandler);
+        return new SimpleStanzaHandlerExecutor(stanzaRelay, stanzaHandler, offlineStanzaReceiver);
     }
 
 }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContext.java b/server/core/src/main/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContext.java
index 0ec8de5..ff1f171 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContext.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/server/DefaultServerRuntimeContext.java
@@ -38,6 +38,7 @@
 import org.apache.vysper.xmpp.addressing.Entity;
 import org.apache.vysper.xmpp.authentication.UserAuthentication;
 import org.apache.vysper.xmpp.cryptography.TLSContextFactory;
+import org.apache.vysper.xmpp.delivery.OfflineStanzaReceiver;
 import org.apache.vysper.xmpp.delivery.StanzaRelay;
 import org.apache.vysper.xmpp.modules.Module;
 import org.apache.vysper.xmpp.modules.ModuleRegistry;
@@ -131,7 +132,7 @@
      */
     private final Map<String, ServerRuntimeContextService> serverRuntimeContextServiceMap = new HashMap<String, ServerRuntimeContextService>();
 
-    private List<Module> modules = new ArrayList<Module>();
+    private List<Module> modules = new ArrayList<>();
 
     /**
      * map of all registered components, index by the subdomain they are registered
@@ -147,12 +148,13 @@
 
     public DefaultServerRuntimeContext(Entity serverEntity, StanzaRelay stanzaRelay, StanzaProcessor stanzaProcessor,
             AlterableComponentRegistry componentRegistry, ResourceRegistry resourceRegistry,
-            ServerFeatures serverFeatures, List<HandlerDictionary> dictionaries) {
+            ServerFeatures serverFeatures, List<HandlerDictionary> dictionaries,
+            OfflineStanzaReceiver offlineStanzaReceiver) {
         this.serverEntity = serverEntity;
         this.stanzaRelay = stanzaRelay;
         this.componentRegistry = requireNonNull(componentRegistry);
         StanzaHandlerExecutorFactory simpleStanzaHandlerExecutorFactory = new SimpleStanzaHandlerExecutorFactory(
-                stanzaRelay);
+                stanzaRelay, offlineStanzaReceiver);
         this.serverConnectorRegistry = new DefaultXMPPServerConnectorRegistry(this, simpleStanzaHandlerExecutorFactory,
                 stanzaProcessor);
         this.stanzaHandlerLookup = new StanzaHandlerLookup(this);
@@ -171,17 +173,17 @@
     }
 
     public DefaultServerRuntimeContext(Entity serverEntity, StanzaRelay stanzaRelay) {
-        this(serverEntity, stanzaRelay, new ProtocolWorker(new SimpleStanzaHandlerExecutorFactory(stanzaRelay)),
+        this(serverEntity, stanzaRelay,
+                new ProtocolWorker(new SimpleStanzaHandlerExecutorFactory(stanzaRelay, null)),
                 new SimpleComponentRegistry(serverEntity), new DefaultResourceRegistry(), new ServerFeatures(),
-                Collections.emptyList());
+                Collections.emptyList(),
+                null);
     }
 
     /**
      * change the presence cache implementation. this is a setter intended to be
      * used at initialisation time. (thus, this method is not part of
      * ServerRuntimeContext.
-     * 
-     * @param presenceCache
      */
     public void setPresenceCache(LatestPresenceCache presenceCache) {
         this.presenceCache = presenceCache;
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/server/XMPPServer.java b/server/core/src/main/java/org/apache/vysper/xmpp/server/XMPPServer.java
index 414313e..9d7799c 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/server/XMPPServer.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/server/XMPPServer.java
@@ -55,7 +55,6 @@
 import org.apache.vysper.xmpp.server.components.SimpleComponentRegistry;
 import org.apache.vysper.xmpp.state.resourcebinding.DefaultResourceRegistry;
 import org.apache.vysper.xmpp.state.resourcebinding.InternalResourceRegistry;
-import org.apache.vysper.xmpp.state.resourcebinding.ResourceRegistry;
 
 /**
  * this class is able to boot a standalone XMPP server. <code>
@@ -190,7 +189,7 @@
         AlterableComponentRegistry componentRegistry = new SimpleComponentRegistry(serverEntity);
 
         DeliveringInternalInboundStanzaRelay internalStanzaRelay = new DeliveringInternalInboundStanzaRelay(
-                serverEntity, resourceRegistry, componentRegistry, accountManagement, offlineReceiver);
+                serverEntity, resourceRegistry, componentRegistry, accountManagement);
         DeliveringExternalInboundStanzaRelay externalStanzaRelay = new DeliveringExternalInboundStanzaRelay();
 
         if (maxInternalRelayThreads >= 0)
@@ -203,12 +202,12 @@
         stanzaRelayBroker.setExternalRelay(externalStanzaRelay);
 
         StanzaHandlerExecutorFactory stanzaHandlerExecutorFactory = new SimpleStanzaHandlerExecutorFactory(
-                stanzaRelayBroker);
+                stanzaRelayBroker, offlineReceiver);
 
         stanzaProcessor = new ProtocolWorker(stanzaHandlerExecutorFactory);
 
         serverRuntimeContext = new DefaultServerRuntimeContext(serverEntity, stanzaRelayBroker, stanzaProcessor,
-                componentRegistry, resourceRegistry, serverFeatures, dictionaries);
+                componentRegistry, resourceRegistry, serverFeatures, dictionaries, offlineReceiver);
         serverRuntimeContext.setStorageProviderRegistry(storageProviderRegistry);
         serverRuntimeContext.setTlsContextFactory(tlsContextFactory);
 
@@ -225,7 +224,7 @@
         if (logStorageProvider != null)
             internalStanzaRelay.setLogStorageProvider(logStorageProvider);
 
-        if (endpoints.size() == 0)
+        if (endpoints.isEmpty())
             throw new IllegalStateException("server must have at least one endpoint");
 
         /*
diff --git a/server/core/src/test/java/org/apache/vysper/stanzasession/StanzaSessionTestCase.java b/server/core/src/test/java/org/apache/vysper/stanzasession/StanzaSessionTestCase.java
index 1e63b3e..53911ad 100644
--- a/server/core/src/test/java/org/apache/vysper/stanzasession/StanzaSessionTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/stanzasession/StanzaSessionTestCase.java
@@ -61,7 +61,7 @@
         ProtocolWorker protocolWorker = new ProtocolWorker(new SimpleStanzaHandlerExecutorFactory(relay));
         DefaultServerRuntimeContext serverContext = new DefaultServerRuntimeContext(serverEntity, relay, protocolWorker,
                 new SimpleComponentRegistry(serverEntity), new DefaultResourceRegistry(), new ServerFeatures(),
-                dictionaries);
+                dictionaries, null);
 
         relay.setServerRuntimeContext(serverContext);
 
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInteralInboundStanzaRelayTestCase.java b/server/core/src/test/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInteralInboundStanzaRelayTestCase.java
index 50bdbe2..054bc15 100644
--- a/server/core/src/test/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInteralInboundStanzaRelayTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInteralInboundStanzaRelayTestCase.java
@@ -88,7 +88,7 @@
         accountVerification = new AccountVerificationMock();
         serverEntity = EntityImpl.parse("vysper.org");
         stanzaRelay = new DeliveringInternalInboundStanzaRelay(serverEntity, resourceRegistry,
-                new SimpleComponentRegistry(serverEntity), accountVerification, null);
+                new SimpleComponentRegistry(serverEntity), accountVerification);
     }
 
     public void testSimpleRelay() throws EntityFormatException, XMLSemanticError, DeliveryException {
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/base/handler/MessageHandlerRelayTestCase.java b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/base/handler/MessageHandlerRelayTestCase.java
index cdd6bf9..324c2ae 100644
--- a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/base/handler/MessageHandlerRelayTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/base/handler/MessageHandlerRelayTestCase.java
@@ -30,7 +30,7 @@
 import org.apache.vysper.xmpp.modules.core.TestUser;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.server.TestSessionContext;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
@@ -92,7 +92,7 @@
 
         Stanza stanza = stanzaBuilder.build();
         messageHandler.execute(stanza, senderSessionContext.getServerRuntimeContext(), true, senderSessionContext, null,
-                new SimpleStanzaBroker(senderSessionContext.getStanzaRelay(), senderSessionContext));
+                new DefaultStanzaBroker(senderSessionContext.getStanzaRelay(), senderSessionContext));
 
         Stanza receivedStanza = receiverUser.getNextStanza();
         XMLElementVerifier timestampVerifier = receivedStanza.getFirstInnerElement().getVerifier();
@@ -119,12 +119,12 @@
 
         Stanza successfulMessageStanza = StanzaBuilder.createMessageStanza(sender, receiver, "en", "info").build();
         messageHandler.execute(successfulMessageStanza, senderSessionContext.getServerRuntimeContext(), true,
-                senderSessionContext, null, new SimpleStanzaBroker(stanzaRelay, senderSessionContext));
+                senderSessionContext, null, new DefaultStanzaBroker(stanzaRelay, senderSessionContext));
         assertEquals(successfulMessageStanza, receiverQueue.getNext());
 
         Stanza failureMessageStanza = StanzaBuilder.createMessageStanza(sender, noReceiver, "en", "info").build();
         messageHandler.execute(failureMessageStanza, senderSessionContext.getServerRuntimeContext(), true,
-                senderSessionContext, null, new SimpleStanzaBroker(stanzaRelay, senderSessionContext));
+                senderSessionContext, null, new DefaultStanzaBroker(stanzaRelay, senderSessionContext));
         assertNull(receiverQueue.getNext());
         Stanza rejectionStanza = senderQueue.getNext();
         assertNotNull(rejectionStanza);
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/base/handler/RelayingIQHandlerTestCase.java b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/base/handler/RelayingIQHandlerTestCase.java
index f004403..c501485 100644
--- a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/base/handler/RelayingIQHandlerTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/base/handler/RelayingIQHandlerTestCase.java
@@ -22,7 +22,7 @@
 import org.apache.vysper.xmpp.modules.core.im.handler.PresenceHandlerBaseTestCase;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
 import org.apache.vysper.xmpp.protocol.RecordingStanzaBroker;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.stanza.IQStanzaType;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
@@ -40,7 +40,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        stanzaBroker = new RecordingStanzaBroker(new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+        stanzaBroker = new RecordingStanzaBroker(new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
     }
 
     public void testIQClientToClient_Outbound_NotSubscribed() {
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/DirectedPresenceHandlerTestCase.java b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/DirectedPresenceHandlerTestCase.java
index abbe900..8877404 100644
--- a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/DirectedPresenceHandlerTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/DirectedPresenceHandlerTestCase.java
@@ -25,7 +25,7 @@
 import org.apache.vysper.xmpp.addressing.Entity;
 import org.apache.vysper.xmpp.addressing.EntityFormatException;
 import org.apache.vysper.xmpp.delivery.StanzaReceiverRelay;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.stanza.PresenceStanza;
 import org.apache.vysper.xmpp.stanza.PresenceStanzaType;
 import org.apache.vysper.xmpp.stanza.Stanza;
@@ -49,7 +49,7 @@
                 .createPresenceStanza(initiatingUser.getEntityFQ(), unrelatedUser.getEntityFQ(), null, null, null, null)
                 .build());
         handler.executeCore(initialPresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(receiverRelay, sessionContext));
+                new DefaultStanzaBroker(receiverRelay, sessionContext));
         assertTrue(0 < receiverRelay.getCountDelivered());
 
         // directed presence has been recorded internally
@@ -71,7 +71,7 @@
                 .getWrapper(StanzaBuilder.createPresenceStanza(initiatingUser.getEntityFQ(),
                         unrelatedUser.getEntityFQ(), null, PresenceStanzaType.UNAVAILABLE, null, null).build());
         handler.executeCore(directedUnvailPresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(receiverRelay, sessionContext));
+                new DefaultStanzaBroker(receiverRelay, sessionContext));
         assertTrue(0 < receiverRelay.getCountDelivered());
 
         // directed presence has been recorded internally
@@ -99,7 +99,7 @@
                 .createPresenceStanza(initiatingUser.getEntityFQ(), unrelatedUser.getEntityFQ(), null, null, null, null)
                 .build());
         handler.executeCore(initialPresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(receiverRelay, sessionContext));
+                new DefaultStanzaBroker(receiverRelay, sessionContext));
 
         // directed presence has been recorded internally
         Set<Entity> map = (Set<Entity>) sessionContext
@@ -113,7 +113,7 @@
                 .getWrapper(StanzaBuilder.createPresenceStanza(initiatingUser.getEntityFQ(), null, null,
                         PresenceStanzaType.UNAVAILABLE, null, null).build());
         handler.executeCore(generalUnavailable, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(receiverRelay, sessionContext));
+                new DefaultStanzaBroker(receiverRelay, sessionContext));
         assertTrue(0 < receiverRelay.getCountDelivered());
         ResourceState resourceState = sessionContext.getServerRuntimeContext().getResourceRegistry()
                 .getResourceState(initiatingUser.getBoundResourceId());
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailInitialOutHandlerTestCase.java b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailInitialOutHandlerTestCase.java
index 24938b7..970eb8f 100644
--- a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailInitialOutHandlerTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailInitialOutHandlerTestCase.java
@@ -27,7 +27,7 @@
 import org.apache.vysper.xml.fragment.XMLSemanticError;
 import org.apache.vysper.xmpp.addressing.EntityFormatException;
 import org.apache.vysper.xmpp.delivery.StanzaReceiverRelay;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
 import org.apache.vysper.xmpp.stanza.StanzaErrorCondition;
@@ -47,7 +47,7 @@
 
         assertEquals(ResourceState.CONNECTED, getResourceState());
         handler.executeCore(initialPresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         // check resource state change, do not override interested
         assertEquals(ResourceState.AVAILABLE, getResourceState());
 
@@ -112,7 +112,7 @@
                 .getWrapper(StanzaBuilder.createPresenceStanza(null, null, null, null, null, null).build());
 
         List<Stanza> stanzas = handler.executeCore(initialPresence, sessionContext.getServerRuntimeContext(), true,
-                sessionContext, new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                sessionContext, new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         Stanza stanza = stanzas.get(0);
         // ... and will give an error:
         assertEquals("error", stanza.getAttribute("type").getValue());
@@ -127,7 +127,7 @@
                 .unbindResource(anotherAvailableUser.getBoundResourceId());
         // 3 other resources got unbound, remaining one should now be unique
         stanzas = handler.executeCore(initialPresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         stanza = stanzas.get(0);
         assertNull(stanza); // no return, esp no error stanza - all the handling is done through relays
         stanza = initiatingUser.getNextStanza();
@@ -141,7 +141,7 @@
                 .unbindResource(initiatingUser.getBoundResourceId());
         assertTrue(noRemainingBinds);
         stanzas = handler.executeCore(initialPresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         stanza = stanzas.get(0);
         assertEquals("error", stanza.getAttribute("type").getValue());
         assertEquals(StanzaErrorCondition.UNKNOWN_SENDER.value(),
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailUpdateOutHandlerTestCase.java b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailUpdateOutHandlerTestCase.java
index 4311cab..c45c9dd 100644
--- a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailUpdateOutHandlerTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailUpdateOutHandlerTestCase.java
@@ -22,7 +22,7 @@
 
 import org.apache.vysper.xmpp.addressing.EntityFormatException;
 import org.apache.vysper.xmpp.delivery.StanzaReceiverRelay;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
 import org.apache.vysper.xmpp.stanza.XMPPCoreStanza;
@@ -42,7 +42,7 @@
         XMPPCoreStanza initialPresence = XMPPCoreStanza.getWrapper(
                 StanzaBuilder.createPresenceStanza(initiatingUser.getEntityFQ(), null, null, null, null, null).build());
         handler.executeCore(initialPresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(receiverRelay, sessionContext));
+                new DefaultStanzaBroker(receiverRelay, sessionContext));
         assertTrue(0 < receiverRelay.getCountDelivered());
         resetRecordedStanzas(); // purge recorded
         assertTrue(0 == receiverRelay.getCountDelivered());
@@ -53,7 +53,7 @@
         XMPPCoreStanza updatePresence = XMPPCoreStanza.getWrapper(StanzaBuilder
                 .createPresenceStanza(initiatingUser.getEntityFQ(), null, null, null, showValue, null).build());
         handler.executeCore(updatePresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(receiverRelay, sessionContext));
+                new DefaultStanzaBroker(receiverRelay, sessionContext));
         // check resource state
         assertEquals(ResourceState.AVAILABLE, getResourceState());
 
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceSubRequestOutHandlerTestCase.java b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceSubRequestOutHandlerTestCase.java
index eaf6e36..9c3ad38 100644
--- a/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceSubRequestOutHandlerTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceSubRequestOutHandlerTestCase.java
@@ -27,7 +27,7 @@
 import org.apache.vysper.xmpp.addressing.EntityFormatException;
 import org.apache.vysper.xmpp.addressing.EntityImpl;
 import org.apache.vysper.xmpp.delivery.StanzaReceiverRelay;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.stanza.PresenceStanzaType;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
@@ -52,7 +52,7 @@
                 .getWrapper(StanzaBuilder.createPresenceStanza(unrelatedUser.getEntityFQ(), initiatingUser.getEntity(),
                         null, PresenceStanzaType.SUBSCRIBED, null, null).build());
         handler.executeCore(requestApproval, sessionContext.getServerRuntimeContext(), false, sessionContext,
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
 
         // 3 roster pushes but...
         StanzaReceiverRelay relay = (StanzaReceiverRelay) sessionContext.getStanzaRelay();
@@ -76,7 +76,7 @@
                         null, PresenceStanzaType.SUBSCRIBE, null, null).build());
 
         handler.executeCore(initialPresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         assertEquals(ResourceState.AVAILABLE_INTERESTED, getResourceState());
 
         // 1 to TO + 3 roster pushes
@@ -126,7 +126,7 @@
                         subscribed_FROM.getEntity(), null, PresenceStanzaType.SUBSCRIBE, null, null).build());
 
         handler.executeCore(initialPresence, sessionContext.getServerRuntimeContext(), true, sessionContext,
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         assertEquals(ResourceState.AVAILABLE_INTERESTED, getResourceState());
 
         // 1 to TO + 3 roster pushes
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/ExtendedDiscoInfoTestCase.java b/server/core/src/test/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/ExtendedDiscoInfoTestCase.java
index cea8ece..10eb1fd 100644
--- a/server/core/src/test/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/ExtendedDiscoInfoTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/ExtendedDiscoInfoTestCase.java
@@ -39,7 +39,7 @@
 import org.apache.vysper.xmpp.modules.servicediscovery.management.ServiceDiscoveryRequestException;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.server.DefaultServerRuntimeContext;
 import org.apache.vysper.xmpp.server.InternalSessionContext;
 import org.apache.vysper.xmpp.server.TestSessionContext;
@@ -91,7 +91,7 @@
                 runtimeContext.getStanzaRelay());
 
         List<Stanza> resultStanzas = infoIQHandler.handleGet(finalStanza, runtimeContext, sessionContext,
-                new SimpleStanzaBroker(runtimeContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(runtimeContext.getStanzaRelay(), sessionContext));
 
         assertTrue(resultStanzas.get(0).getVerifier().onlySubelementEquals("query",
                 NamespaceURIs.XEP0030_SERVICE_DISCOVERY_INFO));
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/server/components/ComponentStanzaProcessorTestCase.java b/server/core/src/test/java/org/apache/vysper/xmpp/server/components/ComponentStanzaProcessorTestCase.java
index de256ae..865b021 100644
--- a/server/core/src/test/java/org/apache/vysper/xmpp/server/components/ComponentStanzaProcessorTestCase.java
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/server/components/ComponentStanzaProcessorTestCase.java
@@ -29,7 +29,7 @@
 import org.apache.vysper.xmpp.delivery.StanzaRelay;
 import org.apache.vysper.xmpp.protocol.ProtocolException;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.protocol.SimpleStanzaHandlerExecutorFactory;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.server.InternalSessionContext;
@@ -97,7 +97,7 @@
         processor.processStanza(serverRuntimeContext, sessionContext, stanza, sessionStateHolder);
 
         verify(handler).execute(stanza, serverRuntimeContext, false, sessionContext, sessionStateHolder,
-                new SimpleStanzaBroker(stanzaRelay, sessionContext));
+                new DefaultStanzaBroker(stanzaRelay, sessionContext));
     }
 
     @Test(expected = RuntimeException.class)
@@ -107,7 +107,7 @@
         // new SimpleStanzaBroker(stanzaRelay, sessionContext))).thenReturn(container);
 
         doThrow(new RuntimeException()).when(handler).execute(stanza, serverRuntimeContext, false, sessionContext,
-                sessionStateHolder, new SimpleStanzaBroker(stanzaRelay, sessionContext));
+                sessionStateHolder, new DefaultStanzaBroker(stanzaRelay, sessionContext));
 
         processor.addHandler(handler);
 
diff --git a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/AbstractMUCOccupantDiscoTestCase.java b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/AbstractMUCOccupantDiscoTestCase.java
index 02f3f6c..f2f2a0f 100644
--- a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/AbstractMUCOccupantDiscoTestCase.java
+++ b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/AbstractMUCOccupantDiscoTestCase.java
@@ -26,7 +26,7 @@
 import org.apache.vysper.xmpp.modules.extension.xep0045_muc.model.Room;
 import org.apache.vysper.xmpp.modules.servicediscovery.collection.ServiceCollector;
 import org.apache.vysper.xmpp.protocol.ProtocolException;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.stanza.IQStanzaType;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
@@ -37,7 +37,7 @@
 
     private Stanza sendDisco(Stanza stanza) throws ProtocolException {
         RecordingStanzaBroker recordingStanzaBroker = new RecordingStanzaBroker(
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
 
         handler.execute(stanza, sessionContext.getServerRuntimeContext(), true,
                 sessionContext, null, recordingStanzaBroker);
diff --git a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/AbstractMUCHandlerTestCase.java b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/AbstractMUCHandlerTestCase.java
index 40e15b1..6df7089 100644
--- a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/AbstractMUCHandlerTestCase.java
+++ b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/AbstractMUCHandlerTestCase.java
@@ -39,7 +39,7 @@
 import org.apache.vysper.xmpp.modules.extension.xep0045_muc.stanzas.X;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
 import org.apache.vysper.xmpp.protocol.ProtocolException;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.stanza.IQStanza;
 import org.apache.vysper.xmpp.stanza.IQStanzaType;
@@ -272,7 +272,7 @@
 
         Stanza iqStanza = stanzaBuilder.build();
 
-        RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+        RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         handler.execute(iqStanza, sessionContext.getServerRuntimeContext(), true, sessionContext, null, stanzaBroker);
         return stanzaBroker.getUniqueStanzaWrittenToSession();
     }
diff --git a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/AbstractMUCMessageHandlerTestCase.java b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/AbstractMUCMessageHandlerTestCase.java
index febacae..906fb0e 100644
--- a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/AbstractMUCMessageHandlerTestCase.java
+++ b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/AbstractMUCMessageHandlerTestCase.java
@@ -28,7 +28,7 @@
 import org.apache.vysper.xmpp.modules.extension.xep0045_muc.model.Room;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
 import org.apache.vysper.xmpp.protocol.ProtocolException;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.stanza.MessageStanzaType;
 import org.apache.vysper.xmpp.stanza.Stanza;
@@ -62,7 +62,7 @@
 
         Stanza messageStanza = stanzaBuilder.build();
         RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         handler.execute(messageStanza, sessionContext.getServerRuntimeContext(), true, sessionContext, null,
                 stanzaBroker);
         return stanzaBroker.getUniqueStanzaWrittenToSession();
diff --git a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ChangeNickTestCase.java b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ChangeNickTestCase.java
index 27e46e7..a33c7d3 100644
--- a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ChangeNickTestCase.java
+++ b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ChangeNickTestCase.java
@@ -32,7 +32,7 @@
 import org.apache.vysper.xmpp.modules.extension.xep0045_muc.stanzas.Status.StatusCode;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
 import org.apache.vysper.xmpp.protocol.ProtocolException;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.stanza.PresenceStanzaType;
 import org.apache.vysper.xmpp.stanza.Stanza;
@@ -51,7 +51,7 @@
         Stanza presenceStanza = stanzaBuilder.build();
 
         RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         handler.execute(presenceStanza, sessionContext.getServerRuntimeContext(), true, sessionContext, null,
                 stanzaBroker);
         return stanzaBroker.getUniqueStanzaWrittenToSession();
diff --git a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ChangeStatusTestCase.java b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ChangeStatusTestCase.java
index e5e44c7..747046c 100644
--- a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ChangeStatusTestCase.java
+++ b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ChangeStatusTestCase.java
@@ -29,7 +29,7 @@
 import org.apache.vysper.xmpp.modules.extension.xep0045_muc.model.Room;
 import org.apache.vysper.xmpp.modules.extension.xep0045_muc.stanzas.MucUserItem;
 import org.apache.vysper.xmpp.protocol.ProtocolException;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
@@ -44,7 +44,7 @@
                 status);
 
         Stanza presenceStanza = stanzaBuilder.build();
-        RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+        RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         handler.execute(presenceStanza, sessionContext.getServerRuntimeContext(), true, sessionContext, null,
                 stanzaBroker);
         return stanzaBroker.getUniqueStanzaWrittenToSession();
diff --git a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/EnterRoomTestCase.java b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/EnterRoomTestCase.java
index ba37ca5..63a246c 100644
--- a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/EnterRoomTestCase.java
+++ b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/EnterRoomTestCase.java
@@ -39,7 +39,7 @@
 import org.apache.vysper.xmpp.modules.extension.xep0045_muc.stanzas.X;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
 import org.apache.vysper.xmpp.protocol.ProtocolException;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.server.SessionContext;
 import org.apache.vysper.xmpp.stanza.MessageStanza;
@@ -78,7 +78,7 @@
         }
         Stanza presenceStanza = stanzaBuilder.build();
         RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         handler.execute(presenceStanza, userSessionContext.getServerRuntimeContext(), true, userSessionContext, null,
                 stanzaBroker);
         return stanzaBroker.getUniqueStanzaWrittenToSession();
diff --git a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ExitRoomTestCase.java b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ExitRoomTestCase.java
index 1774684..f7fb1f6 100644
--- a/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ExitRoomTestCase.java
+++ b/server/extensions/xep0045-muc/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0045_muc/handler/ExitRoomTestCase.java
@@ -31,7 +31,7 @@
 import org.apache.vysper.xmpp.modules.extension.xep0045_muc.model.RoomType;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
 import org.apache.vysper.xmpp.protocol.ProtocolException;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.stanza.PresenceStanzaType;
 import org.apache.vysper.xmpp.stanza.Stanza;
@@ -51,7 +51,7 @@
 
         Stanza presenceStanza = stanzaBuilder.build();
         RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(
-                new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+                new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         handler.execute(presenceStanza, sessionContext.getServerRuntimeContext(), true, sessionContext, null,
                 stanzaBroker);
         return stanzaBroker.getUniqueStanzaWrittenToSession();
diff --git a/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/RecordingStanzaBroker.java b/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/RecordingStanzaBroker.java
index d742af8..c536080 100644
--- a/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/RecordingStanzaBroker.java
+++ b/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/RecordingStanzaBroker.java
@@ -25,12 +25,9 @@
 import java.util.List;
 
 import org.apache.vysper.xmpp.addressing.Entity;
-import org.apache.vysper.xmpp.delivery.StanzaRelay;
 import org.apache.vysper.xmpp.delivery.failure.DeliveryException;
 import org.apache.vysper.xmpp.delivery.failure.DeliveryFailureStrategy;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
 import org.apache.vysper.xmpp.protocol.StanzaBroker;
-import org.apache.vysper.xmpp.server.SessionContext;
 import org.apache.vysper.xmpp.stanza.Stanza;
 
 /**
diff --git a/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0060_pubsub/AbstractPublishSubscribeTestCase.java b/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0060_pubsub/AbstractPublishSubscribeTestCase.java
index 4193130..8faf009 100644
--- a/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0060_pubsub/AbstractPublishSubscribeTestCase.java
+++ b/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0060_pubsub/AbstractPublishSubscribeTestCase.java
@@ -31,7 +31,7 @@
 import org.apache.vysper.xmpp.modules.extension.xep0060_pubsub.storageprovider.LeafNodeInMemoryStorageProvider;
 import org.apache.vysper.xmpp.modules.servicediscovery.collection.ServiceCollector;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.server.DefaultServerRuntimeContext;
 import org.apache.vysper.xmpp.server.SessionState;
 import org.apache.vysper.xmpp.stanza.Stanza;
@@ -152,7 +152,7 @@
     protected abstract AbstractStanzaGenerator getDefaultStanzaGenerator();
 
     protected Stanza sendStanza(Stanza toSend, boolean isOutboundStanza) {
-        RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(new SimpleStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
+        RecordingStanzaBroker stanzaBroker = new RecordingStanzaBroker(new DefaultStanzaBroker(sessionContext.getStanzaRelay(), sessionContext));
         handler.execute(toSend, sessionContext.getServerRuntimeContext(), isOutboundStanza, sessionContext, null,
                 stanzaBroker);
         return stanzaBroker.getUniqueStanzaWrittenToSession();
diff --git a/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0060_pubsub/disco/PubSubDiscoItemsTestCase.java b/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0060_pubsub/disco/PubSubDiscoItemsTestCase.java
index 127cba6..5e26253 100644
--- a/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0060_pubsub/disco/PubSubDiscoItemsTestCase.java
+++ b/server/extensions/xep0060-pubsub/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0060_pubsub/disco/PubSubDiscoItemsTestCase.java
@@ -31,7 +31,7 @@
 import org.apache.vysper.xmpp.modules.extension.xep0060_pubsub.model.LeafNode;
 import org.apache.vysper.xmpp.modules.servicediscovery.handler.DiscoItemIQHandler;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
-import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
+import org.apache.vysper.xmpp.protocol.DefaultStanzaBroker;
 import org.apache.vysper.xmpp.stanza.IQStanza;
 import org.apache.vysper.xmpp.stanza.IQStanzaType;
 import org.apache.vysper.xmpp.stanza.Stanza;
@@ -151,17 +151,17 @@
         XMLElement item1 = new XMLElement("namespace1", "item1", null, (Attribute[]) null, (XMLFragment[]) null);
         XMLElement item2 = new XMLElement("namespace2", "item2", null, (Attribute[]) null, (XMLFragment[]) null);
         XMLElement item3 = new XMLElement("namespace3", "item3", null, (Attribute[]) null, (XMLFragment[]) null);
-        node.publish(client, new SimpleStanzaBroker(relay, sessionContext), "itemid1", item1);
+        node.publish(client, new DefaultStanzaBroker(relay, sessionContext), "itemid1", item1);
         Thread.sleep(10);
-        node.publish(client, new SimpleStanzaBroker(relay, sessionContext), "itemid2", item1); // publish this one with
+        node.publish(client, new DefaultStanzaBroker(relay, sessionContext), "itemid2", item1); // publish this one with
                                                                                                // the same id as the
                                                                                                // next one (overwritten
         // by the next)
-        node.publish(client, new SimpleStanzaBroker(relay, sessionContext), "itemid2", item2); // overwrite the prev.
+        node.publish(client, new DefaultStanzaBroker(relay, sessionContext), "itemid2", item2); // overwrite the prev.
                                                                                                // item (use the same
                                                                                                // itemid)
         Thread.sleep(10);
-        node.publish(client, new SimpleStanzaBroker(relay, sessionContext), "itemid3", item3);
+        node.publish(client, new DefaultStanzaBroker(relay, sessionContext), "itemid3", item3);
 
         DefaultDiscoInfoStanzaGenerator sg = (DefaultDiscoInfoStanzaGenerator) getDefaultStanzaGenerator();
         Stanza stanza = sg.getStanza(client, pubsubService.getBareJID(), "id123", "news");
diff --git a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserMessageStanzaBroker.java b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserMessageStanzaBroker.java
index 9e6f77c..3ef8a6a 100644
--- a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserMessageStanzaBroker.java
+++ b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserMessageStanzaBroker.java
@@ -27,7 +27,6 @@
 import org.apache.vysper.xml.fragment.XMLElement;
 import org.apache.vysper.xml.fragment.XMLSemanticError;
 import org.apache.vysper.xmpp.addressing.Entity;
-import org.apache.vysper.xmpp.addressing.EntityUtils;
 import org.apache.vysper.xmpp.delivery.failure.DeliveryException;
 import org.apache.vysper.xmpp.delivery.failure.DeliveryFailureStrategy;
 import org.apache.vysper.xmpp.modules.core.base.handler.XMPPCoreStanzaHandler;
@@ -79,9 +78,6 @@
     }
 
     private Stanza archive(Stanza stanza) {
-        if (!isOutbound) {
-            return stanza;
-        }
         if (!MessageStanza.isOfType(stanza)) {
             return stanza;
         }
@@ -108,10 +104,13 @@
         }
 
         // TODO Check preferences
-
-        addToSenderArchive(messageStanza, sessionContext);
-        return addToReceiverArchive(messageStanza).map(MessageStanzaWithId::new).map(MessageStanzaWithId::toStanza)
-                .orElse(stanza);
+        if (isOutbound) {
+            addToSenderArchive(messageStanza, sessionContext);
+            return messageStanza;
+        } else {
+            return addToReceiverArchive(messageStanza).map(MessageStanzaWithId::new).map(MessageStanzaWithId::toStanza)
+                    .orElse(stanza);
+        }
     }
 
     private void addToSenderArchive(MessageStanza messageStanza, SessionContext sessionContext) {
@@ -127,11 +126,6 @@
     }
 
     private Optional<ArchivedMessage> addToReceiverArchive(MessageStanza messageStanza) {
-        Entity to = requireNonNull(messageStanza.getTo(), "No 'to' found in " + messageStanza);
-        if (!EntityUtils.isAddressingServer(to, serverRuntimeContext.getServerEntity())) {
-            LOG.debug("Receiver {} is not managed by this server", to);
-            return Optional.empty();
-        }
         // Servers that expose archive messages of sent/received messages on behalf of
         // local users MUST expose these archives to the user on the user's bare JID.
         Entity receiverArchiveId = requireNonNull(messageStanza.getTo(), "No 'to' found in " + messageStanza)
diff --git a/server/extensions/xep0313-mam/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserArchiveTest.java b/server/extensions/xep0313-mam/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserArchiveTest.java
index a8cf981..bef02b9 100644
--- a/server/extensions/xep0313-mam/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserArchiveTest.java
+++ b/server/extensions/xep0313-mam/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserArchiveTest.java
@@ -219,10 +219,16 @@
 
         Thread.sleep(200);
 
-        assertNull(carolReceivedMessage.get());
+        assertNotNull(carolReceivedMessage.get());
+        assertEquals("Hello carol", carolReceivedMessage.get().getBody());
 
-        Message message = fetchUniqueArchivedMessage(carol());
-        assertEquals("Hello carol", message.getBody());
+        Message archivedMessage = fetchUniqueArchivedMessage(carol());
+        String storedStanzaId = extractStanzaId(archivedMessage);
+        assertNotNull(storedStanzaId);
+
+        String receivedStanzaId = extractStanzaId(carolReceivedMessage.get());
+
+        assertEquals(storedStanzaId, receivedStanzaId);
     }
 
     @Test