Bernd, could you please review this commit. I'm not very experienced with how IQ stanza relaying is supposed to work.
/niklas On Tue, Mar 22, 2011 at 11:40 PM, <[email protected]> wrote: > Author: ngn > Date: Tue Mar 22 22:40:49 2011 > New Revision: 1084393 > > URL: http://svn.apache.org/viewvc?rev=1084393&view=rev > Log: > Implement relaying of IQ stanzas and disco IQ stanzas to a user with a full > JID provided (VYSPER-278) > > Modified: > > mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java > > mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandler.java > > mina/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandlerTestCase.java > > Modified: > mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java > URL: > http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java?rev=1084393&r1=1084392&r2=1084393&view=diff > ============================================================================== > --- > mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java > (original) > +++ > mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java > Tue Mar 22 22:40:49 2011 > @@ -232,7 +232,7 @@ public class DeliveringInternalInboundSt > } > } else if (IQStanza.isOfType(stanza)) { > // TODO handle on behalf of the user/client > - throw new RuntimeException("inbound IQ not yet handled"); > + return relayToBestSessions(false); > } > > return relayNotPossible(); > > Modified: > mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandler.java > URL: > http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandler.java?rev=1084393&r1=1084392&r2=1084393&view=diff > ============================================================================== > --- > mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandler.java > (original) > +++ > mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandler.java > Tue Mar 22 22:40:49 2011 > @@ -25,6 +25,8 @@ import org.apache.vysper.compliance.Spec > import org.apache.vysper.compliance.SpecCompliant; > import org.apache.vysper.xml.fragment.XMLElement; > import org.apache.vysper.xmpp.addressing.Entity; > +import org.apache.vysper.xmpp.delivery.failure.DeliveryException; > +import > org.apache.vysper.xmpp.delivery.failure.ReturnErrorToSenderFailureStrategy; > import org.apache.vysper.xmpp.modules.core.base.handler.DefaultIQHandler; > import > org.apache.vysper.xmpp.modules.servicediscovery.collection.ServiceCollector; > import > org.apache.vysper.xmpp.modules.servicediscovery.collection.ServiceDiscoveryRequestListenerRegistry; > @@ -58,7 +60,8 @@ public class DiscoInfoIQHandler extends > > @Override > protected boolean verifyInnerElement(Stanza stanza) { > - return verifyInnerElementWorker(stanza, "query") && > verifyInnerNamespace(stanza, NamespaceURIs.XEP0030_SERVICE_DISCOVERY_INFO); > + return verifyInnerElementWorker(stanza, "query") > + && verifyInnerNamespace(stanza, > NamespaceURIs.XEP0030_SERVICE_DISCOVERY_INFO); > } > > @Override > @@ -78,8 +81,8 @@ public class DiscoInfoIQHandler extends > } > > if (serviceCollector == null) { > - return > ServerErrorResponses.getStanzaError(StanzaErrorCondition.INTERNAL_SERVER_ERROR, > - stanza, StanzaErrorType.CANCEL, "cannot retrieve > IQ-get-info result from internal components", > + return > ServerErrorResponses.getStanzaError(StanzaErrorCondition.INTERNAL_SERVER_ERROR, > stanza, > + StanzaErrorType.CANCEL, "cannot retrieve IQ-get-info > result from internal components", > getErrorLanguage(serverRuntimeContext, sessionContext), > null); > } > > @@ -109,25 +112,30 @@ public class DiscoInfoIQHandler extends > List<InfoElement> elements = null; > try { > Entity from = stanza.getFrom(); > - if (from == null) from = sessionContext.getInitiatingEntity(); > + if (from == null) > + from = sessionContext.getInitiatingEntity(); > if (isServerInfoRequest) { > - elements = serviceCollector.processServerInfoRequest(new > InfoRequest(from, to, node, stanza > - .getID())); > + elements = serviceCollector.processServerInfoRequest(new > InfoRequest(from, to, node, stanza.getID())); > } else if (isComponentInfoRequest) { > - elements = serviceCollector.processComponentInfoRequest(new > InfoRequest(from, to, node, > - stanza.getID())); > + elements = serviceCollector > + .processComponentInfoRequest(new InfoRequest(from, > to, node, stanza.getID())); > } else { > - elements = serviceCollector.processInfoRequest(new > InfoRequest(from, to, node, stanza > - .getID())); > + // "When an entity sends a disco#info request to a bare JID > (<[email protected]>) hosted by a server, > + // the server itself MUST reply on behalf of the hosted > account, either with an IQ-error or an IQ-result" > + if (to.isResourceSet()) { > + relayOrWrite(stanza, serverRuntimeContext, > sessionContext); > + return null; > + } else { > + elements = serviceCollector.processInfoRequest(new > InfoRequest(from, to, node, stanza.getID())); > + } > } > } catch (ServiceDiscoveryRequestException e) { > // the request yields an error > StanzaErrorCondition stanzaErrorCondition = e.getErrorCondition(); > if (stanzaErrorCondition == null) > stanzaErrorCondition = > StanzaErrorCondition.INTERNAL_SERVER_ERROR; > - return ServerErrorResponses.getStanzaError(stanzaErrorCondition, > stanza, > - StanzaErrorType.CANCEL, "disco info request failed.", > - getErrorLanguage(serverRuntimeContext, sessionContext), > null); > + return ServerErrorResponses.getStanzaError(stanzaErrorCondition, > stanza, StanzaErrorType.CANCEL, > + "disco info request failed.", > getErrorLanguage(serverRuntimeContext, sessionContext), null); > } > > //TODO check that elementSet contains at least one identity element > and on feature element! > @@ -146,4 +154,36 @@ public class DiscoInfoIQHandler extends > > return stanzaBuilder.build(); > } > + > + @Override > + protected Stanza handleResult(IQStanza stanza, ServerRuntimeContext > serverRuntimeContext, > + SessionContext sessionContext) { > + > + if (stanza.getTo().isResourceSet()) { > + relayOrWrite(stanza, serverRuntimeContext, sessionContext); > + return null; > + } else { > + return super.handleResult(stanza, serverRuntimeContext, > sessionContext); > + } > + } > + > + private void relayOrWrite(IQStanza stanza, ServerRuntimeContext > serverRuntimeContext, SessionContext sessionContext) { > + boolean isOutbound = > !sessionContext.getInitiatingEntity().equals(stanza.getTo().getBareJID()); > + if (isOutbound) { > + try { > + Entity from = stanza.getFrom(); > + if (from == null) { > + from = sessionContext.getInitiatingEntity(); > + } > + Stanza forward = StanzaBuilder.createForwardStanza(stanza, > from, null); > + > + serverRuntimeContext.getStanzaRelay().relay(stanza.getTo(), > forward, > + new > ReturnErrorToSenderFailureStrategy(serverRuntimeContext.getStanzaRelay())); > + } catch (DeliveryException e) { > + logger.warn("relaying IQ failed", e); > + } > + } else { > + sessionContext.getResponseWriter().write(stanza); > + } > + } > } > > Modified: > mina/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandlerTestCase.java > URL: > http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandlerTestCase.java?rev=1084393&r1=1084392&r2=1084393&view=diff > ============================================================================== > --- > mina/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandlerTestCase.java > (original) > +++ > mina/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/modules/servicediscovery/handler/DiscoInfoIQHandlerTestCase.java > Tue Mar 22 22:40:49 2011 > @@ -27,6 +27,8 @@ import junit.framework.Assert; > import org.apache.vysper.StanzaAssert; > import org.apache.vysper.xmpp.addressing.Entity; > import org.apache.vysper.xmpp.addressing.EntityImpl; > +import org.apache.vysper.xmpp.delivery.StanzaRelay; > +import org.apache.vysper.xmpp.delivery.failure.DeliveryFailureStrategy; > import > org.apache.vysper.xmpp.modules.servicediscovery.collection.ServiceCollector; > import > org.apache.vysper.xmpp.modules.servicediscovery.collection.ServiceDiscoveryRequestListenerRegistry; > import org.apache.vysper.xmpp.modules.servicediscovery.management.Feature; > @@ -44,6 +46,7 @@ import org.apache.vysper.xmpp.stanza.Sta > import org.apache.vysper.xmpp.stanza.StanzaBuilder; > import org.apache.vysper.xmpp.stanza.StanzaErrorCondition; > import org.apache.vysper.xmpp.stanza.XMPPCoreStanza; > +import org.apache.vysper.xmpp.writer.StanzaWriter; > import org.junit.Before; > import org.junit.Test; > import org.mockito.Mockito; > @@ -56,10 +59,13 @@ public class DiscoInfoIQHandlerTestCase > private static final Entity SERVER = > EntityImpl.parseUnchecked("vysper.org"); > private static final Entity COMPONENT = > EntityImpl.parseUnchecked("comp.vysper.org"); > private static final Entity USER = > EntityImpl.parseUnchecked("[email protected]"); > + private static final Entity USER_WITH_RESOURCE = > EntityImpl.parseUnchecked("[email protected]/res1"); > > - private ServerRuntimeContext serverRuntimeContext = > Mockito.mock(ServerRuntimeContext.class); > - private SessionContext sessionContext = > Mockito.mock(SessionContext.class); > - private ServiceCollector serviceCollector = > Mockito.mock(ServiceCollector.class); > + private ServerRuntimeContext serverRuntimeContext = > mock(ServerRuntimeContext.class); > + private SessionContext sessionContext = mock(SessionContext.class); > + private ServiceCollector serviceCollector = mock(ServiceCollector.class); > + private StanzaRelay stanzaRelay = mock(StanzaRelay.class); > + private StanzaWriter stanzaWriter = mock(StanzaWriter.class); > > private IQStanza stanza = (IQStanza) IQStanza.getWrapper(buildStanza()); > > @@ -148,6 +154,8 @@ public class DiscoInfoIQHandlerTestCase > .thenReturn(serviceCollector); > > when(serverRuntimeContext.getServerEnitity()).thenReturn(SERVER); > + when(serverRuntimeContext.getStanzaRelay()).thenReturn(stanzaRelay); > + when(sessionContext.getResponseWriter()).thenReturn(stanzaWriter); > } > > @Test > @@ -186,6 +194,32 @@ public class DiscoInfoIQHandlerTestCase > } > > @Test > + public void handleGetToUserWithResource() throws Exception { > + when(sessionContext.getInitiatingEntity()).thenReturn(FROM); > + > + IQStanza stanza = createRequest(USER_WITH_RESOURCE); > + > + Stanza response = handler.handleGet(stanza, serverRuntimeContext, > sessionContext); > + > + Assert.assertNull(response); > + > + verify(stanzaRelay).relay(eq(USER_WITH_RESOURCE), eq(stanza), > any(DeliveryFailureStrategy.class)); > + } > + > + @Test > + public void handleGetToUserWithResourceInbound() throws Exception { > + when(sessionContext.getInitiatingEntity()).thenReturn(USER); > + > + IQStanza stanza = createRequest(USER_WITH_RESOURCE); > + > + Stanza response = handler.handleGet(stanza, serverRuntimeContext, > sessionContext); > + > + Assert.assertNull(response); > + > + verify(stanzaWriter).write(stanza); > + } > + > + @Test > public void handleGetToNonExistingComponent() throws Exception { > IQStanza stanza = createRequest(COMPONENT); > > @@ -253,6 +287,45 @@ public class DiscoInfoIQHandlerTestCase > StanzaAssert.assertEquals(expected, response); > } > > + @Test > + public void handleResultToUserWithResource() throws Exception { > + when(sessionContext.getInitiatingEntity()).thenReturn(FROM); > + > + IQStanza stanza = createRequest(USER_WITH_RESOURCE, > IQStanzaType.RESULT); > + > + Stanza response = handler.handleResult(stanza, serverRuntimeContext, > sessionContext); > + > + Assert.assertNull(response); > + > + verify(stanzaRelay).relay(eq(USER_WITH_RESOURCE), eq(stanza), > any(DeliveryFailureStrategy.class)); > + } > + > + @Test > + public void handleResultToUserWithResourceInbound() throws Exception { > + when(sessionContext.getInitiatingEntity()).thenReturn(USER); > + > + IQStanza stanza = createRequest(USER_WITH_RESOURCE, > IQStanzaType.RESULT); > + > + Stanza response = handler.handleResult(stanza, serverRuntimeContext, > sessionContext); > + > + Assert.assertNull(response); > + > + verify(stanzaWriter).write(stanza); > + } > + > + @Test > + public void handleResultToUser() throws Exception { > + when(sessionContext.getInitiatingEntity()).thenReturn(FROM); > + > + IQStanza stanza = createRequest(USER, IQStanzaType.RESULT); > + > + Stanza response = handler.handleResult(stanza, serverRuntimeContext, > sessionContext); > + > + Stanza expected = createErrorResponse(SERVER, > "feature-not-implemented"); > + > + StanzaAssert.assertEquals(expected, response); > + } > + > private Stanza createErrorResponse(Entity from, String error) { > Stanza expected = StanzaBuilder.createIQStanza(from, FROM, > IQStanzaType.ERROR, "id1") > .startInnerElement("query", > NamespaceURIs.XEP0030_SERVICE_DISCOVERY_INFO) > @@ -266,7 +339,11 @@ public class DiscoInfoIQHandlerTestCase > } > > private IQStanza createRequest(Entity to) { > - IQStanza stanza = (IQStanza) > XMPPCoreStanza.getWrapper(StanzaBuilder.createIQStanza(FROM, to, > IQStanzaType.GET, "id1") > + return createRequest(to, IQStanzaType.GET); > + } > + > + private IQStanza createRequest(Entity to, IQStanzaType type) { > + IQStanza stanza = (IQStanza) > XMPPCoreStanza.getWrapper(StanzaBuilder.createIQStanza(FROM, to, type, "id1") > .startInnerElement("query", > NamespaceURIs.XEP0030_SERVICE_DISCOVERY_INFO) > .addAttribute("node", "n") > .build()); > > >
