2016-03-23 8 views
1

weiß jemand zufällig, ob es sinnvoll ist, einen Service-Aktivator und damit auch den Output-Kanal mit mehreren Methoden (Inbound) insbesondere mit Splitter und Aggregator wiederzuverwenden.Wiederverwendung von Service-Aktivator für mehrere Gateway-Methoden mit Splitter

-> Immer mit Ergebnis auf dem Gateway.

In mehreren Tests scheint es gut zu funktionieren. Sobald ich einen Splitter mit einem Aggregator hinzugefügt habe, bekomme ich Unannehmlichkeiten, die zum Gateway geroutet werden, was dann mit einer Konvertierungsausnahme fehlschlägt (hier in meinem Fall kann es nicht boolesch in Ganzzahl konvertiert werden).

Danke,

Paul

Fluss

Spring Integration Flow

Frühling Integration Config

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:int="http://www.springframework.org/schema/integration" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
     http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"> 

    <int:gateway service-interface="activity.BulbMessageGateway"> 
     <int:method name="sendToBulb" request-channel="bulbMessages" reply-channel="bulbSendResult"></int:method> 
     <int:method name="updateHomeLightStatus" request-channel="homeBulbEntity" reply-channel="homeBulbEntityResult"> 
     </int:method> 
     <int:method name="updateLightStatus" request-channel="bulbEntities" reply-channel="bulbSendResult"> 
      <int:header name="homeId" expression="#args[0].homeId"/> 
      <int:header name="bulbId" expression="#args[0].strongId"/> 
     </int:method> 
    </int:gateway> 

    <int:channel id="bulbMessages" /> 
    <int:channel id="bulbSendResult" /> 
    <int:channel id="bulbEntities" /> 

    <int:channel id="homeBulbEntity" /> 
    <int:channel id="homeBulbEntityResult" /> 

    <int:chain input-channel="homeBulbEntity" output-channel="bulbEntities"> 
     <int:splitter expression="payload.bulbs" /> 
     <int:header-enricher> 
      <int:header name="bulbId" expression="payload.strongId"/> 
      <int:header name="homeId" expression="payload.homeId"/> 
     </int:header-enricher> 
    </int:chain> 

    <int:transformer method="bulbToLightStatus" input-channel="bulbEntities" output-channel="bulbMessages"> 
     <bean class="util.BulbTransformer"></bean> 
    </int:transformer> 

    <int:aggregator input-channel="bulbSendResult" output-channel="homeBulbEntityResult" method="aggregate"> 
     <bean class="util.BooleanAggregator" /> 
    </int:aggregator> 

    <int:service-activator input-channel="bulbMessages" output-channel="bulbSendResult" method="send"> 
     <bean class="activity.BulbWebsocketMessageSenderBA" /> 
    </int:service-activator> 
</beans> 

Unit-Test

@Test 
public void sendMessageNoReceiver() { 
    assertFalse(gateway.sendToBulb(new HomeId("1"), new BulbId("1"), BulbMessageBuilder.restart("foo"))); 
} 

@Test 
public void sendMessageWithReceiver() { 
    MockSession<BulbId, BulbBE> bulbSession = new MockSession<BulbId, BulbBE>(new BulbBE(HomeId.of("1"), BulbId.of("1"), "bulb", "pass")); 
    registry.addBulbSession(bulbSession); 
    assertTrue(gateway.sendToBulb(new HomeId("1"), new BulbId("1"), BulbMessageBuilder.restart("foo"))); 
    assertEquals(1, bulbSession.receivedMessages()); 
} 

@Test 
public void updateBulbStatus() { 
    final MockSession<BulbId, BulbBE> bulbSession1 = new MockSession<BulbId, BulbBE>(new BulbBE(HomeId.of("1"), BulbId.of("1"), "bulb", "pass")); 
    assertFalse(gateway.updateLightStatus(bulbSession1.getIdentity())); 

    registry.addBulbSession(bulbSession1); 
    assertTrue(gateway.updateLightStatus(bulbSession1.getIdentity())); 
    assertEquals(1, bulbSession1.receivedMessages()); 

    final MockSession<BulbId, BulbBE> bulbSession2 = new MockSession<BulbId, BulbBE>(new BulbBE(HomeId.of("1"), BulbId.of("2"), "bulb", "pass")); 
    assertFalse(gateway.updateLightStatus(bulbSession2.getIdentity())); 

    registry.addBulbSession(bulbSession2); 
    assertTrue(gateway.updateLightStatus(bulbSession2.getIdentity())); 
    assertTrue(gateway.updateLightStatus(bulbSession2.getIdentity())); 

    assertEquals(2, bulbSession2.receivedMessages()); 
    assertEquals(1, bulbSession1.receivedMessages()); 
} 
@Test 
public void updateHomeBulbStatus() { 
    final HomeBE home = new HomeBE(); 
    home.setId(new ObjectId()); 

    final MockSession<BulbId, BulbBE> bulbSession1 = new MockSession<BulbId, BulbBE>(new BulbBE(home.getStrongId(), BulbId.of("1"), "bulb", "pass")); 
    registry.addBulbSession(bulbSession1); 
    final MockSession<BulbId, BulbBE> bulbSession2 = new MockSession<BulbId, BulbBE>(new BulbBE(home.getStrongId(), BulbId.of("2"), "bulb", "pass")); 
    registry.addBulbSession(bulbSession2); 

    home.addBulb(bulbSession1.getIdentity()); 

    assertEquals(1, gateway.updateHomeLightStatus(home)); 
    assertEquals(1, bulbSession1.receivedMessages()); 
    assertEquals(0, bulbSession2.receivedMessages()); 

    home.addBulb(bulbSession2.getIdentity()); 
    assertEquals(2, gateway.updateHomeLightStatus(home)); 
    assertEquals(2, bulbSession1.receivedMessages()); 
    assertEquals(1, bulbSession2.receivedMessages()); 
} 

Der letzte Test schlägt fehl, wenn er zusammen mit den anderen Tests ausgeführt wird. Es wird übergeben, wenn es alleine ausgeführt wird.

Der Fehler ist, dass die letzte Methode (mit dem Splitter) jetzt einen booleschen Wert erhält, der ein Ergebnis der beiden anderen registrierten Methoden zu sein scheint. Das Ergebnis dieser Methoden ist ein boolescher Wert.

+0

- BooleanAggregator zählt wahren Werte - BulbTransformer führt die Konvertierung der Art der Dienst in dem Aktivator erwartet * Methode: sendToBulb nur die Nachricht sendet als ist * Methode: updateLightStatus die Nachricht sendet, sondern nur wandelt einmal * Methode: updateHomeLightStatus sendet nun eine Collection, die Teil des gegebenen Arguments ist und mit einem Splitter-Ausdruck extrahiert wurde. * payload.bulbs * – Paul

+0

Verschieben Sie dies auch zu Ihrer Frage. –

Antwort

1

Bitte teilen Sie die Konfiguration in der Sache.

Und entsprechend Ihrer Grafik wäre es besser, wenn Sie die Konfiguration so weit wie möglich minimieren würden, um das Problem zu isolieren.

Von anderer Seite, bitte, genauer: Ihre Frage ist völlig unklar.

Das ist Ihr eigenes Service. Wie können wir sicher sein, dass es sicher ist, an verschiedenen Orten verwendet zu werden? Nur Sie als Autor können das feststellen.

UPDATE

Sorry für die Verspätung. War mit der Veröffentlichung beschäftigt.

Und danke für die Freigabe der Konfiguration für Ihren Anwendungsfall.

Jetzt sehe ich das Problem.

Sie verwenden überall auf den Gateway-Methoden eine reply-channel. Siehe die documentation über die Angelegenheit, wenn Sie brauchen, dass:

Typischerweise Sie nicht den default-Antwort-Kanal angeben müssen, da ein Gateway einen temporären, anonymen Antwortkanal automatisch erstellen, wo sie hören für die Antwort. Es gibt jedoch Fälle, in denen Sie aufgefordert werden, einen Standardantwortkanal (oder Antwortkanal mit Adaptergateways wie HTTP, JMS usw.) zu definieren.

Da Sie die gleiche bulbSendResult an verschiedenen Orten das Verhalten verwenden ist wirklich unberechenbar. Außerdem ist dieser Kanal DirectChannel, also sind die round-robin Balancer auf der Szene.

Sie sollten diese reply-channel 's überhaupt loswerden und verlassen Sie sich nur von Ihren nachgelagerten Komponenten auf dem replyChannel Header. Daher sollten Sie diese output-channel s in den Komponenten entfernen, die Antworten auf Ihr Gateway zurückgeben sollen.

Zum Beispiel der letzten service-activator wie dies gerade sein sollen:

<int:service-activator input-channel="bulbMessages" method="send"> 
    <bean class="activity.BulbWebsocketMessageSenderBA"/> 
</int:service-activator> 

Da Sie allgemeine Frage, wie man diese service-activator wieder zu verwenden, ich bin auf die Frage zu beantworten, die Config von Ihnen mit:

<int:chain input-channel="homeBulbEntity"> 
    <int:splitter expression="payload.bulbs"/> 
    <int:header-enricher> 
     <int:header name="bulbId" expression="payload.strongId"/> 
     <int:header name="homeId" expression="payload.homeId"/> 
    </int:header-enricher> 
    <int:transformer method="bulbToLightStatus"> 
     <bean class="util.BulbTransformer"/> 
    </int:transformer> 
    <int:gateway request-channel="bulbMessages"/> 
    <int:aggregator method="aggregate"> 
     <bean class="util.BooleanAggregator"/> 
    </int:aggregator> 
</int:chain> 

Achten Sie auf die fehlende output-channel für die <chain>. Daher sendet es die Antwort direkt an die replyChannel von Header und als return an Ihre updateHomeLightStatus Gateway-Methode.

Ein weiterer Trick ist, dass <int:gateway request-channel="bulbMessages"/>, welche Nachrichten in der Mitte des <chain> Flusses zum <service-activator> und warten auf die Antwort von dort sendet genau die gleiche Weise wie ein Top-Level-Gateway - über replyChannel Header. Für die <service-activator> ohne eine ist es eine Black-Box, wo die Antwort zu senden. Es verwendet nur replyChannel aus Headern!

Nach Erhalt der Antwort gateway im <chain> drücken Sie die Nachricht an die <aggregator>.

Wenn aggregator seine Logik ausführt, wird das Ergebnis als Ausgabe vom <chain> an das Gateway der obersten Ebene gesendet.

Das ist alles.

Lassen Sie mich wissen, was sonst hier nicht klar ist.

+0

Xml-Konfiguration und Test hinzugefügt, hoffe es hilft – Paul

+0

Sorry für die Verzögerung sowieso, aber, bitte, finden Sie ein Update in meiner Antwort. –

+0

Awesome, vielen Dank Artem! Das hilft wirklich. Schon beim Lesen sehe ich, was ich falsch gemacht habe. Cooler Trick mit dem Paul