You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by ra...@apache.org on 2019/09/01 18:18:07 UTC

[mina-vysper] branch master updated: Allow to intercept the StanzaHandler execution

This is an automated email from the ASF dual-hosted git repository.

ralaoui pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-vysper.git


The following commit(s) were added to refs/heads/master by this push:
     new 7c9fff7  Allow to intercept the StanzaHandler execution
7c9fff7 is described below

commit 7c9fff7ea864222c377344e8cb26be90f1edd9a5
Author: Réda Housni Alaoui <re...@gmail.com>
AuthorDate: Sun Sep 1 20:17:58 2019 +0200

    Allow to intercept the StanzaHandler execution
---
 .../vysper/stanzasession/StanzaSessionFactory.java |   1 +
 .../apache/vysper/xmpp/modules/DefaultModule.java  |   7 +
 .../org/apache/vysper/xmpp/modules/Module.java     |   3 +
 .../xmpp/protocol/SimpleStanzaHandlerExecutor.java |   9 +-
 .../SimpleStanzaHandlerInterceptorChain.java       |  66 ++++++++++
 .../xmpp/protocol/StanzaHandlerExecutor.java       |   5 +-
 .../StanzaHandlerInterceptor.java}                 |  14 +-
 .../StanzaHandlerInterceptorChain.java}            |  11 +-
 .../xmpp/server/DefaultServerRuntimeContext.java   |  17 ++-
 .../xmpp/server/InternalServerRuntimeContext.java  |   4 +-
 .../vysper/xmpp/server/ServerRuntimeContext.java   |   3 +
 .../SimpleStanzaHandlerInterceptorChainTest.java   | 144 +++++++++++++++++++++
 .../ComponentStanzaProcessorTestCase.java          |  23 +---
 13 files changed, 264 insertions(+), 43 deletions(-)

diff --git a/server/core/src/main/java/org/apache/vysper/stanzasession/StanzaSessionFactory.java b/server/core/src/main/java/org/apache/vysper/stanzasession/StanzaSessionFactory.java
index 23b3627..d9f4795 100644
--- a/server/core/src/main/java/org/apache/vysper/stanzasession/StanzaSessionFactory.java
+++ b/server/core/src/main/java/org/apache/vysper/stanzasession/StanzaSessionFactory.java
@@ -22,6 +22,7 @@ package org.apache.vysper.stanzasession;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
 import org.apache.vysper.xmpp.protocol.StanzaProcessor;
 import org.apache.vysper.xmpp.server.Endpoint;
+import org.apache.vysper.xmpp.server.InternalServerRuntimeContext;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.SessionState;
 
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/modules/DefaultModule.java b/server/core/src/main/java/org/apache/vysper/xmpp/modules/DefaultModule.java
index e8c2e4b..6804eed 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/modules/DefaultModule.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/modules/DefaultModule.java
@@ -20,11 +20,13 @@
 package org.apache.vysper.xmpp.modules;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
 
 import org.apache.vysper.event.EventListenerDictionary;
 import org.apache.vysper.xmpp.protocol.HandlerDictionary;
+import org.apache.vysper.xmpp.protocol.StanzaHandlerInterceptor;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 
 /**
@@ -49,6 +51,11 @@ public abstract class DefaultModule implements Module {
     }
 
     @Override
+    public List<StanzaHandlerInterceptor> getStanzaHandlerInterceptors() {
+        return Collections.emptyList();
+    }
+
+    @Override
     public Optional<EventListenerDictionary> getEventListenerDictionary() {
         return Optional.empty();
     }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/modules/Module.java b/server/core/src/main/java/org/apache/vysper/xmpp/modules/Module.java
index 2a9ef08..47562ce 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/modules/Module.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/modules/Module.java
@@ -24,6 +24,7 @@ import java.util.Optional;
 
 import org.apache.vysper.event.EventListenerDictionary;
 import org.apache.vysper.xmpp.protocol.HandlerDictionary;
+import org.apache.vysper.xmpp.protocol.StanzaHandlerInterceptor;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.XMPPServer;
 
@@ -59,6 +60,8 @@ public interface Module {
      * all stanza handler dictionaries to be added to the server
      */
     List<HandlerDictionary> getHandlerDictionaries();
+    
+    List<StanzaHandlerInterceptor> getStanzaHandlerInterceptors();
 
     /**
      * @return The event listener dictionary to be added to the server
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 6da7693..25e28f8 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
@@ -22,8 +22,8 @@ package org.apache.vysper.xmpp.protocol;
 import static java.util.Objects.requireNonNull;
 
 import org.apache.vysper.xmpp.delivery.StanzaRelay;
-import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.InternalSessionContext;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.stanza.Stanza;
 
 /**
@@ -42,8 +42,11 @@ class SimpleStanzaHandlerExecutor implements StanzaHandlerExecutor {
 
     @Override
     public void execute(Stanza stanza, ServerRuntimeContext serverRuntimeContext, boolean isOutboundStanza,
-						InternalSessionContext sessionContext, SessionStateHolder sessionStateHolder) throws ProtocolException {
-        stanzaHandler.execute(stanza, serverRuntimeContext, isOutboundStanza, sessionContext, sessionStateHolder,
+            InternalSessionContext sessionContext, SessionStateHolder sessionStateHolder) throws ProtocolException {
+        StanzaHandlerInterceptorChain interceptorChain = new SimpleStanzaHandlerInterceptorChain(stanzaHandler,
+                serverRuntimeContext.getStanzaHandlerInterceptors());
+
+        interceptorChain.intercept(stanza, serverRuntimeContext, isOutboundStanza, sessionContext, sessionStateHolder,
                 new SimpleStanzaBroker(stanzaRelay, sessionContext));
     }
 
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerInterceptorChain.java b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerInterceptorChain.java
new file mode 100644
index 0000000..0f3c07a
--- /dev/null
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerInterceptorChain.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *  
+ */
+package org.apache.vysper.xmpp.protocol;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.stanza.Stanza;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+class SimpleStanzaHandlerInterceptorChain implements StanzaHandlerInterceptorChain {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SimpleStanzaHandlerInterceptorChain.class);
+
+    private final StanzaHandler stanzaHandler;
+
+    private final Queue<StanzaHandlerInterceptor> interceptors;
+
+    public SimpleStanzaHandlerInterceptorChain(StanzaHandler stanzaHandler,
+            List<StanzaHandlerInterceptor> interceptors) {
+        this.stanzaHandler = requireNonNull(stanzaHandler);
+        this.interceptors = new LinkedList<>(interceptors);
+    }
+
+    @Override
+    public void intercept(Stanza stanza, ServerRuntimeContext serverRuntimeContext, boolean isOutboundStanza,
+            SessionContext sessionContext, SessionStateHolder sessionStateHolder, StanzaBroker stanzaBroker)
+            throws ProtocolException {
+        StanzaHandlerInterceptor interceptor = interceptors.poll();
+        if (interceptor == null) {
+            LOG.debug("No more interceptor to execute. Executing stanza handler {}.", stanzaHandler);
+            stanzaHandler.execute(stanza, serverRuntimeContext, isOutboundStanza, sessionContext, sessionStateHolder,
+                    stanzaBroker);
+            return;
+        }
+        LOG.debug("Executing interceptor {}", interceptor);
+        interceptor.intercept(stanza, serverRuntimeContext, isOutboundStanza, sessionContext, sessionStateHolder,
+                stanzaBroker, this);
+    }
+}
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerExecutor.java b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerExecutor.java
index d80e2b4..55aa582 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerExecutor.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerExecutor.java
@@ -19,9 +19,9 @@
  */
 package org.apache.vysper.xmpp.protocol;
 
+import org.apache.vysper.xmpp.server.InternalSessionContext;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.SessionContext;
-import org.apache.vysper.xmpp.server.InternalSessionContext;
 import org.apache.vysper.xmpp.stanza.Stanza;
 
 /**
@@ -39,6 +39,5 @@ import org.apache.vysper.xmpp.stanza.Stanza;
  */
 public interface StanzaHandlerExecutor {
     void execute(Stanza stanza, ServerRuntimeContext serverRuntimeContext, boolean isOutboundStanza,
-				 InternalSessionContext sessionContext, SessionStateHolder sessionStateHolder)
-            throws ProtocolException;
+            InternalSessionContext sessionContext, SessionStateHolder sessionStateHolder) throws ProtocolException;
 }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerInterceptor.java
similarity index 61%
copy from server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java
copy to server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerInterceptor.java
index 9a8d0d7..8e43793 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerInterceptor.java
@@ -17,15 +17,19 @@
  *  under the License.
  *  
  */
-package org.apache.vysper.xmpp.server;
+package org.apache.vysper.xmpp.protocol;
 
-import org.apache.vysper.xmpp.server.s2s.XMPPServerConnectorRegistry;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.stanza.Stanza;
 
 /**
  * @author Réda Housni Alaoui
  */
-public interface InternalServerRuntimeContext extends ServerRuntimeContext {
+public interface StanzaHandlerInterceptor {
+
+    void intercept(Stanza stanza, ServerRuntimeContext serverRuntimeContext, boolean isOutboundStanza,
+            SessionContext sessionContext, SessionStateHolder sessionStateHolder, StanzaBroker stanzaBroker,
+            StanzaHandlerInterceptorChain interceptorChain) throws ProtocolException;
 
-	XMPPServerConnectorRegistry getServerConnectorRegistry();
-	
 }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerInterceptorChain.java
similarity index 64%
copy from server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java
copy to server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerInterceptorChain.java
index 9a8d0d7..befe690 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/StanzaHandlerInterceptorChain.java
@@ -17,15 +17,18 @@
  *  under the License.
  *  
  */
-package org.apache.vysper.xmpp.server;
+package org.apache.vysper.xmpp.protocol;
 
-import org.apache.vysper.xmpp.server.s2s.XMPPServerConnectorRegistry;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.stanza.Stanza;
 
 /**
  * @author Réda Housni Alaoui
  */
-public interface InternalServerRuntimeContext extends ServerRuntimeContext {
+public interface StanzaHandlerInterceptorChain {
 
-	XMPPServerConnectorRegistry getServerConnectorRegistry();
+	void intercept(Stanza stanza, ServerRuntimeContext serverRuntimeContext, boolean isOutboundStanza,
+				   SessionContext sessionContext, SessionStateHolder sessionStateHolder, StanzaBroker stanzaBroker) throws ProtocolException;
 	
 }
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 94aef67..0ec8de5 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
@@ -47,6 +47,7 @@ import org.apache.vysper.xmpp.protocol.ProtocolWorker;
 import org.apache.vysper.xmpp.protocol.SimpleStanzaHandlerExecutorFactory;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.protocol.StanzaHandlerExecutorFactory;
+import org.apache.vysper.xmpp.protocol.StanzaHandlerInterceptor;
 import org.apache.vysper.xmpp.protocol.StanzaHandlerLookup;
 import org.apache.vysper.xmpp.protocol.StanzaProcessor;
 import org.apache.vysper.xmpp.server.components.AlterableComponentRegistry;
@@ -142,6 +143,8 @@ public class DefaultServerRuntimeContext implements InternalServerRuntimeContext
 
     private final ComponentStanzaProcessorFactory componentStanzaProcessorFactory;
 
+    private final List<StanzaHandlerInterceptor> stanzaHandlerInterceptors = new ArrayList<>();
+
     public DefaultServerRuntimeContext(Entity serverEntity, StanzaRelay stanzaRelay, StanzaProcessor stanzaProcessor,
             AlterableComponentRegistry componentRegistry, ResourceRegistry resourceRegistry,
             ServerFeatures serverFeatures, List<HandlerDictionary> dictionaries) {
@@ -150,14 +153,13 @@ public class DefaultServerRuntimeContext implements InternalServerRuntimeContext
         this.componentRegistry = requireNonNull(componentRegistry);
         StanzaHandlerExecutorFactory simpleStanzaHandlerExecutorFactory = new SimpleStanzaHandlerExecutorFactory(
                 stanzaRelay);
-        this.serverConnectorRegistry = new DefaultXMPPServerConnectorRegistry(this,
-                simpleStanzaHandlerExecutorFactory, stanzaProcessor);
+        this.serverConnectorRegistry = new DefaultXMPPServerConnectorRegistry(this, simpleStanzaHandlerExecutorFactory,
+                stanzaProcessor);
         this.stanzaHandlerLookup = new StanzaHandlerLookup(this);
         this.eventBus = new SimpleEventBus();
         this.serverFeatures = serverFeatures;
         this.resourceRegistry = resourceRegistry;
-        this.componentStanzaProcessorFactory = new ComponentStanzaProcessorFactory(
-                simpleStanzaHandlerExecutorFactory);
+        this.componentStanzaProcessorFactory = new ComponentStanzaProcessorFactory(simpleStanzaHandlerExecutorFactory);
 
         addDictionaries(dictionaries);
     }
@@ -383,6 +385,8 @@ public class DefaultServerRuntimeContext implements InternalServerRuntimeContext
             registerComponent((Component) module);
         }
 
+        stanzaHandlerInterceptors.addAll(module.getStanzaHandlerInterceptors());
+
         modules.add(module);
     }
 
@@ -406,6 +410,11 @@ public class DefaultServerRuntimeContext implements InternalServerRuntimeContext
     }
 
     @Override
+    public List<StanzaHandlerInterceptor> getStanzaHandlerInterceptors() {
+        return stanzaHandlerInterceptors;
+    }
+
+    @Override
     public void registerComponent(Component component) {
         componentRegistry.registerComponent(componentStanzaProcessorFactory, component);
     }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java b/server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java
index 9a8d0d7..331da7c 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/server/InternalServerRuntimeContext.java
@@ -26,6 +26,6 @@ import org.apache.vysper.xmpp.server.s2s.XMPPServerConnectorRegistry;
  */
 public interface InternalServerRuntimeContext extends ServerRuntimeContext {
 
-	XMPPServerConnectorRegistry getServerConnectorRegistry();
-	
+    XMPPServerConnectorRegistry getServerConnectorRegistry();
+
 }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/server/ServerRuntimeContext.java b/server/core/src/main/java/org/apache/vysper/xmpp/server/ServerRuntimeContext.java
index b05babf..2c5f02f 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/server/ServerRuntimeContext.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/server/ServerRuntimeContext.java
@@ -31,6 +31,7 @@ import org.apache.vysper.xmpp.authentication.UserAuthentication;
 import org.apache.vysper.xmpp.modules.Module;
 import org.apache.vysper.xmpp.modules.ServerRuntimeContextService;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
+import org.apache.vysper.xmpp.protocol.StanzaHandlerInterceptor;
 import org.apache.vysper.xmpp.server.components.Component;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.state.presence.LatestPresenceCache;
@@ -77,4 +78,6 @@ public interface ServerRuntimeContext {
     void addModule(Module module);
 
     EventBus getEventBus();
+
+    List<StanzaHandlerInterceptor> getStanzaHandlerInterceptors();
 }
diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerInterceptorChainTest.java b/server/core/src/test/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerInterceptorChainTest.java
new file mode 100644
index 0000000..7dc40c5
--- /dev/null
+++ b/server/core/src/test/java/org/apache/vysper/xmpp/protocol/SimpleStanzaHandlerInterceptorChainTest.java
@@ -0,0 +1,144 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *  
+ */
+package org.apache.vysper.xmpp.protocol;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.stanza.Stanza;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public class SimpleStanzaHandlerInterceptorChainTest {
+
+    private StanzaHandler stanzaHandler;
+
+    private Stanza stanza;
+
+    private ServerRuntimeContext serverRuntimeContext;
+
+    private SessionContext sessionContext;
+
+    private SessionStateHolder sessionStateHolder;
+
+    private StanzaBroker firstStanzaBroker;
+
+    @Before
+    public void before() {
+        stanzaHandler = mock(StanzaHandler.class);
+
+        stanza = mock(Stanza.class);
+        serverRuntimeContext = mock(ServerRuntimeContext.class);
+        sessionContext = mock(SessionContext.class);
+        sessionStateHolder = mock(SessionStateHolder.class);
+        firstStanzaBroker = mock(StanzaBroker.class);
+    }
+
+    @Test
+    public void test_no_interceptors() throws ProtocolException {
+        new SimpleStanzaHandlerInterceptorChain(stanzaHandler, Collections.emptyList()).intercept(stanza,
+                serverRuntimeContext, false, sessionContext, sessionStateHolder, firstStanzaBroker);
+
+        verify(stanzaHandler).execute(stanza, serverRuntimeContext, false, sessionContext, sessionStateHolder,
+                firstStanzaBroker);
+    }
+
+    @Test
+    public void test_two_interceptors() throws ProtocolException {
+        List<StanzaHandlerInterceptor> interceptors = new ArrayList<>();
+        interceptors.add(new InterceptorMock());
+        interceptors.add(new InterceptorMock());
+
+        new SimpleStanzaHandlerInterceptorChain(stanzaHandler, interceptors).intercept(stanza, serverRuntimeContext,
+                false, sessionContext, sessionStateHolder, firstStanzaBroker);
+
+        verify(stanzaHandler).execute(stanza, serverRuntimeContext, false, sessionContext, sessionStateHolder,
+                firstStanzaBroker);
+
+        assertTrue(((InterceptorMock) interceptors.get(0)).intercepted);
+        assertTrue(((InterceptorMock) interceptors.get(1)).intercepted);
+    }
+
+    @Test
+    public void test_stanzabroker_substitution_chaining() throws ProtocolException {
+        StanzaBroker secondStanzaBroker = mock(StanzaBroker.class);
+        StanzaBroker thirdStanzaBroker = mock(StanzaBroker.class);
+
+        InterceptorMock firstInterceptor = new InterceptorMock().replaceStanzaBroker(secondStanzaBroker);
+        InterceptorMock secondInterceptor = new InterceptorMock().replaceStanzaBroker(thirdStanzaBroker);
+
+        List<StanzaHandlerInterceptor> interceptors = new ArrayList<>();
+        interceptors.add(firstInterceptor);
+        interceptors.add(secondInterceptor);
+
+        new SimpleStanzaHandlerInterceptorChain(stanzaHandler, interceptors).intercept(stanza, serverRuntimeContext,
+                false, sessionContext, sessionStateHolder, firstStanzaBroker);
+
+        assertEquals(firstStanzaBroker, firstInterceptor.receivedStanzaBroker);
+        assertEquals(secondStanzaBroker, secondInterceptor.receivedStanzaBroker);
+
+        verify(stanzaHandler).execute(stanza, serverRuntimeContext, false, sessionContext, sessionStateHolder,
+                thirdStanzaBroker);
+
+    }
+
+    private static class InterceptorMock implements StanzaHandlerInterceptor {
+
+        private boolean intercepted;
+
+        private StanzaBroker receivedStanzaBroker;
+
+        private StanzaBroker replacingStanzaBroker;
+
+        public InterceptorMock replaceStanzaBroker(StanzaBroker replacingStanzaBroker) {
+            this.replacingStanzaBroker = replacingStanzaBroker;
+            return this;
+        }
+
+        @Override
+        public void intercept(Stanza stanza, ServerRuntimeContext serverRuntimeContext, boolean isOutboundStanza,
+                SessionContext sessionContext, SessionStateHolder sessionStateHolder, StanzaBroker stanzaBroker,
+                StanzaHandlerInterceptorChain interceptorChain) throws ProtocolException {
+
+            receivedStanzaBroker = stanzaBroker;
+
+            intercepted = true;
+
+            if (replacingStanzaBroker != null) {
+                stanzaBroker = replacingStanzaBroker;
+            }
+
+            interceptorChain.intercept(stanza, serverRuntimeContext, isOutboundStanza, sessionContext,
+                    sessionStateHolder, stanzaBroker);
+        }
+    }
+
+}
\ No newline at end of file
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 f17cd65..de256ae 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
@@ -32,14 +32,13 @@ import org.apache.vysper.xmpp.protocol.SessionStateHolder;
 import org.apache.vysper.xmpp.protocol.SimpleStanzaBroker;
 import org.apache.vysper.xmpp.protocol.SimpleStanzaHandlerExecutorFactory;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
-import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.InternalSessionContext;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
 import org.apache.vysper.xmpp.writer.StanzaWriter;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Mockito;
 
 /**
  */
@@ -61,8 +60,6 @@ public class ComponentStanzaProcessorTestCase {
 
     private Stanza stanza = StanzaBuilder.createMessageStanza(FROM, TO, null, "body").build();
 
-    private Stanza responseStanza = StanzaBuilder.createMessageStanza(TO, FROM, null, "response").build();
-
     private ComponentStanzaProcessor processor = new ComponentStanzaProcessor(
             new SimpleStanzaHandlerExecutorFactory(stanzaRelay));
 
@@ -94,15 +91,6 @@ public class ComponentStanzaProcessorTestCase {
     }
 
     @Test
-    public void processSuccessfulNoResponse() {
-        processor.addHandler(handler);
-
-        processor.processStanza(serverRuntimeContext, sessionContext, stanza, sessionStateHolder);
-
-        Mockito.verifyZeroInteractions(serverRuntimeContext);
-    }
-
-    @Test
     public void processSuccessfulWithResponse() throws ProtocolException {
         processor.addHandler(handler);
 
@@ -112,15 +100,6 @@ public class ComponentStanzaProcessorTestCase {
                 new SimpleStanzaBroker(stanzaRelay, sessionContext));
     }
 
-    @Test
-    public void handlerThrowsException() {
-        processor.addHandler(handler);
-
-        processor.processStanza(serverRuntimeContext, sessionContext, stanza, sessionStateHolder);
-
-        Mockito.verifyZeroInteractions(serverRuntimeContext);
-    }
-
     @Test(expected = RuntimeException.class)
     public void processThenFailRelaying() throws ProtocolException {
         // when(handler.execute(stanza, serverRuntimeContext, false, sessionContext,