SI4.0.x: Create a new SI4.0.x maint branch

JIRA: https://jira.spring.io/browse/INTSAMPLES-138

Revert usage of SI 4.0
Remove those samples, which are based on SI 4.1
This commit is contained in:
Artem Bilan
2014-10-28 15:38:36 +02:00
parent 63232c2974
commit 832971cf52
29 changed files with 16 additions and 1767 deletions

View File

@@ -1,50 +0,0 @@
WebSockets Stomp Chat Sample
==============
This application demonstrates the Web chat based on STOMP WebSocket sub-protocol with Spring Integration Adapters.
## Server
The server is presented only with a single `org.springframework.integration.samples.websocket.standard.server.Application`
class, which is based on the Spring Boot AutoConfiguration and Spring Integration xml configuration `@ImportResource`.
It is a `main` and starts an embedded Tomcat server on the default `8080` port.
The WebSocket endpoint is mapped to the `/chat` path.
The server also can be run from Gradle `gradlew :stomp-chat:run`
The server application demonstrates how Spring Integration can be used as a STOMP Broker.
1. `webSocketSessionStore` - the `SimpleMetadataStore` to keep track of `WebSocketSession` and its `user`.
2. `chatMessagesStore` - the `SimpleMessageStore` to store messages for chat rooms.
3. `chatRoomSessions` - the `Map<String, Tuple2<String, String>>` to keep track of `WebSocketSession` `subscriptions`
to the concrete chat room - STOMP `destination`.
4. `<int-event:inbound-channel-adapter channel="routeStompEvents">` is subscribed to the `AbstractSubProtocolEvent`
type to handle STOMP sub-protocol events.
5. `<int:payload-type-router input-channel="routeStompEvents">` is mapped to the appropriate `AbstractSubProtocolEvent`
type to provide the specific integration flow for each event type.
6. `<int-websocket:inbound-channel-adapter>` receives STOMP messages, store them to the appropriate `messageGroup`
(according to the STOMP `destination`) and forward to the `<int-websocket:outbound-channel-adapter>` to send to
each `WebSocketSession` subscribed to that STOMP `destination` - chat room.
## Client
The `index.html` in the `src/main/resources/static` directory of this project demonstrates a JavaScript `STOMP` client
over `SockJS` client.
This application covers classical STOMP scenario:
- `connect` - requirement to enter the `user name` - chat member;
- `subscribe` - the `Join` operation on the one of chat rooms and receiving messages to that subscription for the
destination;
- `send` and `receive` - just chat messages;
- `unsubscribe` - the `Leave` operation on the chat room: the current web socket session stops receiving messages for
the destination;
- `disconnect` - close current web socket session and unsubscribe from all its subscriptions.
To get real chat interaction it's just enough to open several tabs in browser.
When the user joins to the chat room, his subscription receives all messages, sent by other users to that room,
immediately.
## Test Case
The `org.springframework.integration.samples.chat.stomp.server.ApplicationTests` demonstrates the Spring Boot test
framework and just starts Server on the random port to be sure that this application is run correctly.

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed 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.springframework.integration.samples.chat.stomp.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
* @author Artem Bilan
* @since 3.0
*/
@Configuration
@EnableAutoConfiguration
@ImportResource("classpath:org/springframework/integration/samples/chat/stomp/server/stomp-server.xml")
public class Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
System.out.println("Hit 'Enter' to terminate");
System.in.read();
ctx.close();
}
}

View File

@@ -1,142 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-websocket="http://www.springframework.org/schema/integration/websocket"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int-event="http://www.springframework.org/schema/integration/event"
xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"
xmlns:int-groovy="http://www.springframework.org/schema/integration/groovy"
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
http://www.springframework.org/schema/integration/event
http://www.springframework.org/schema/integration/event/spring-integration-event.xsd
http://www.springframework.org/schema/integration/websocket
http://www.springframework.org/schema/integration/websocket/spring-integration-websocket.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/integration/groovy
http://www.springframework.org/schema/integration/groovy/spring-integration-groovy.xsd">
<int:wire-tap channel="logger"/>
<int:logging-channel-adapter id="logger" level="INFO" log-full-message="true"/>
<task:executor id="executor"/>
<bean id="webSocketSessionStore" class="org.springframework.integration.metadata.SimpleMetadataStore"/>
<bean id="chatMessagesStore" class="org.springframework.integration.store.SimpleMessageStore"/>
<util:map id="chatRoomSessions" value-type="java.util.List">
<entry key="room1" value="#{new java.util.ArrayList()}"/>
<entry key="room2" value="#{new java.util.ArrayList()}"/>
</util:map>
<bean id="stompSubProtocolHandler" class="org.springframework.web.socket.messaging.StompSubProtocolHandler"/>
<int-websocket:server-container id="serverWebSocketContainer" path="/chat">
<int-websocket:sockjs/>
</int-websocket:server-container>
<int-event:inbound-channel-adapter event-types="org.springframework.web.socket.messaging.AbstractSubProtocolEvent"
payload-expression="message"
channel="routeStompEvents"/>
<int:header-value-router input-channel="routeStompEvents"
header-name="simpMessageType"
resolution-required="false"
default-output-channel="nullChannel">
<int:mapping value="#{T(org.springframework.messaging.simp.SimpMessageType).CONNECT.name()}"
channel="connectAck"/>
<int:mapping value="#{T(org.springframework.messaging.simp.SimpMessageType).SUBSCRIBE.name()}"
channel="subscribe"/>
<int:mapping value="#{T(org.springframework.messaging.simp.SimpMessageType).UNSUBSCRIBE.name()}"
channel="unsubscribe"/>
<int:mapping value="#{T(org.springframework.messaging.simp.SimpMessageType).DISCONNECT.name()}"
channel="disconnect"/>
</int:header-value-router>
<int:outbound-channel-adapter id="connectAck"
expression="@webSocketSessionStore.put(headers.simpSessionId, headers.nativeHeaders.login)"/>
<int:publish-subscribe-channel id="subscribe"/>
<int:service-activator input-channel="subscribe" output-channel="nullChannel"
expression="@chatRoomSessions[headers.simpDestination]
.add(T(reactor.tuple.Tuple).of(headers.simpSessionId, headers.simpSubscriptionId))"/>
<int:chain input-channel="subscribe" output-channel="sendMessage">
<int:header-enricher>
<int:header name="sessionToSend" expression="headers.simpSessionId"/>
<int:header name="subscriptionToSend" expression="headers.simpSubscriptionId"/>
</int:header-enricher>
<int:service-activator
expression="@chatMessagesStore.getMessageGroup(headers.simpDestination).messages"/>
<int:filter expression="!payload.empty"/>
<int:header-enricher default-overwrite="true">
<int:header name="#{T(org.springframework.messaging.simp.stomp.StompHeaderAccessor).SESSION_ID_HEADER}"
expression="headers.sessionToSend"/>
<int:header
name="#{T(org.springframework.messaging.simp.stomp.StompHeaderAccessor).STOMP_SUBSCRIPTION_HEADER}"
expression="headers.subscriptionToSend"/>
</int:header-enricher>
<int:splitter apply-sequence="false"/>
</int:chain>
<int:outbound-channel-adapter id="unsubscribe">
<int-groovy:script>
chatRoomSessions.each { k, v ->
v.remove(reactor.tuple.Tuple.of(headers.simpSessionId, headers.simpSubscriptionId))
}
null
</int-groovy:script>
</int:outbound-channel-adapter>
<int:channel id="receiveMessage"/>
<int-websocket:inbound-channel-adapter channel="receiveMessage" container="serverWebSocketContainer"
default-protocol-handler="stompSubProtocolHandler"/>
<int:transformer input-channel="receiveMessage" output-channel="storeMessageAndPublish"
expression="{user: @webSocketSessionStore.get(headers.simpSessionId), message: payload, date: new java.util.Date()}"/>
<int:publish-subscribe-channel id="storeMessageAndPublish"/>
<int:service-activator input-channel="storeMessageAndPublish" output-channel="nullChannel"
expression="@chatMessagesStore.addMessageToGroup(headers.simpDestination, #root)"/>
<int:splitter input-channel="storeMessageAndPublish" output-channel="sendMessage" apply-sequence="false">
<int-groovy:script>
chatRoomSessions[headers.simpDestination].collect {
org.springframework.integration.support.MessageBuilder.withPayload(payload)
.copyHeaders(headers)
.setHeader('simpSessionId', it.t1)
.setHeader('simpSubscriptionId', it.t2)
.build()
}
</int-groovy:script>
</int:splitter>
<int:channel id="sendMessage">
<int:dispatcher task-executor="executor"/>
</int:channel>
<int-websocket:outbound-channel-adapter channel="sendMessage" container="serverWebSocketContainer"
default-protocol-handler="stompSubProtocolHandler"/>
<int:outbound-channel-adapter id="disconnect">
<int-groovy:script>
webSocketSessionStore.remove(headers.simpSessionId)
chatRoomSessions.each { k, v -> v.removeAll { it.t1 == headers.simpSessionId } }
null
</int-groovy:script>
</int:outbound-channel-adapter>
</beans>

View File

@@ -1,217 +0,0 @@
<html>
<head>
<title>WebSocket Chat</title>
<script src="http://localhost:8080/sockjs.js"></script>
<script src="http://localhost:8080/stomp.js"></script>
<script type="text/javascript">
var sock, stompClient, currentUser, subscriptions = {};
function connect() {
var userValue = document.getElementById('user');
if (userValue.value != "") {
currentUser = userValue.value;
sock = new SockJS('http://localhost:8080/chat');
stompClient = Stomp.over(sock);
stompClient.connect({login: currentUser}, function (frame) {
document.getElementById("welcome").style.display = "none";
document.getElementById("chat").style.display = "";
document.getElementById("currentUser").innerHTML = currentUser;
userValue.value = "";
});
}
}
function subscribeToRoom(room) {
subscriptions[room] =
stompClient.subscribe('room' + room, function (message) {
var m = JSON.parse(message.body);
var tr = document.createElement('tr');
tr.innerHTML = "<td width='100'><div class='messageUser'>" +
m.user +
"</div><div class='messageDate'>" +
new Date(m.date).toLocaleTimeString(navigator.userLanguage,
{month: "short", day: "numeric", hour: "2-digit", minute: "2-digit"}) +
"</div></td><td>" +
m.message +
"</td>";
var messages = document.getElementById("messages" + room);
messages.appendChild(tr);
messages.scrollIntoView(false);
});
document.getElementById("join" + room).style.display = "none";
document.getElementById("leave" + room).style.display = "";
document.getElementById("message" + room).disabled = false;
document.getElementById("send" + room).disabled = false;
}
function sendMessage(room) {
var messageValue = document.getElementById("message" + room);
if (messageValue.value != "") {
stompClient.send('room' + room, {subscription: subscriptions[room].id}, messageValue.value);
messageValue.value = "";
}
}
function unsubscribeFromRoom(room) {
subscriptions[room].unsubscribe();
document.getElementById("join" + room).style.display = "";
document.getElementById("leave" + room).style.display = "none";
document.getElementById("message" + room).disabled = true;
document.getElementById("send" + room).disabled = true;
document.getElementById("messages" + room).innerHTML = "";
}
function disconnect() {
for (var key in subscriptions) {
if (subscriptions.hasOwnProperty(key)) {
unsubscribeFromRoom(key)
}
}
stompClient.disconnect(function (frame) {
document.getElementById("welcome").style.display = "";
document.getElementById("chat").style.display = "none";
});
}
</script>
<style>
.messageUser {
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
}
.messageDate {
text-align: center;
margin-top: 5px;
}
</style>
</head>
<body style="margin: 0">
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript!
WebSocket relies on Javascript being enabled. Please enable Javascript and reload this page!</h2></noscript>
<div id="welcome"
style="position: absolute;
bottom: 0;
font-size: 200%;
height: 200px;
margin: auto;
text-align: center;
top: 0;
width: 100%;">
Welcome to the Simple WebSocket Stomp Chat!
<br/>
Enter your name to connect:
<br/>
<br/>
<div align="center">
<form onsubmit="connect();return false;">
<table>
<tr>
<td>
<input id="user" type="text"
style="font-size: 24pt; width: 200px; font-weight: bold; margin-top: 2px;"/>
</td>
<td>
<input type="submit" value="Connect"
style="height: 43px; width: 200px; font-size: 24pt; font-weight: bold;"/>
</td>
</tr>
</table>
</form>
</div>
</div>
<div id="chat" align="center" style="font-size: 200%; padding-top: 50px; display: none;">
Welcome, <span id="currentUser"></span>!
<br/>
Please, join to chat rooms to send and receive messages to/from other users:
<br/>
<br/>
<table>
<tr>
<td style="padding-right: 20px;">
<div align="center" style="font-size: 25pt;">
Room 1
</div>
<div align="center">
<input id="join1" type="button" value="Join"
onclick="subscribeToRoom(1)"
style="height: 43px; width: 150px; font-size: 20pt; font-weight: bold;"/>
&nbsp;&nbsp;&nbsp;
<input id="leave1" type="button" value="Leave"
onclick="unsubscribeFromRoom(1)"
style="height: 43px; width: 150px; font-size: 20pt; font-weight: bold;display: none"/>
</div>
<br/>
<div style="height: 300px; border: 5px groove; overflow: auto; width: 500px;">
<table width="100%" border="1" cellspacing="0" style="border: 0">
<tbody id="messages1" valign="top">
</tbody>
</table>
</div>
<br/>
<form onsubmit="sendMessage(1);return false;" style="margin-left: -4px;">
<table>
<tr>
<td>
<input id="message1" type="text" disabled
style="font-size: 20pt; width: 429px; margin-top: 2px;"/>
</td>
<td>
<input id="send1" type="submit" value="Send" disabled
style="height: 40px; width: 77px; font-size: 20pt; font-weight: bold;"/>
</td>
</tr>
</table>
</form>
</td>
<td style="padding-left: 20px;">
<div align="center" style="font-size: 25pt;">
Room 2
</div>
<div align="center">
<input id="join2" type="button" value="Join"
onclick="subscribeToRoom(2)"
style="height: 43px; width: 150px; font-size: 20pt; font-weight: bold;"/>
&nbsp;&nbsp;&nbsp;
<input id="leave2" type="button" value="Leave"
onclick="unsubscribeFromRoom(2)"
style="height: 43px; width: 150px; font-size: 20pt; font-weight: bold; display: none"/>
</div>
<br/>
<div style="height: 300px; border: 5px groove; overflow: auto; width: 500px;">
<table width="100%" border="1" cellspacing="0" style="border: 0">
<tbody id="messages2" valign="top">
</tbody>
</table>
</div>
<br/>
<form onsubmit="sendMessage(2);return false;" style="margin-left: -4px;">
<table>
<tr>
<td>
<input id="message2" type="text" disabled
style="font-size: 20pt; width: 429px; margin-top: 2px;"/>
</td>
<td>
<input id="send2" type="submit" value="Send" disabled
style="height: 40px; width: 77px; font-size: 20pt; font-weight: bold;"/>
</td>
</tr>
</table>
</form>
</td>
</tr>
</table>
<br/><br/>
<input type="button" value="Disconnect" onclick="disconnect()"
style="height: 43px; width: 220px; font-size: 24pt; font-weight: bold;"/>
</div>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,42 +0,0 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed 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.springframework.integration.samples.chat.stomp.server;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
/**
* @author Artem Bilan
* @since 3.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
public class ApplicationTests {
@Test
public void testWebSockets() throws InterruptedException {
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.samples.mongodb.util;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
@@ -24,6 +26,7 @@ import org.springframework.util.StringUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
*
* @author Oleg Zhurakousky
@@ -33,8 +36,9 @@ public class StringConverter extends MappingMongoConverter {
public StringConverter(
MongoDbFactory mongoDbFactory,
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
super(mongoDbFactory, mappingContext);
super(new DefaultDbRefResolver(mongoDbFactory), mappingContext);
}
@Override
public void write(Object source, DBObject target) {
String strPerson = (String) source;
@@ -52,14 +56,12 @@ public class StringConverter extends MappingMongoConverter {
@SuppressWarnings("unchecked")
@Override
public <S> S read(Class<S> clazz, DBObject source) {
StringBuffer buffer = new StringBuffer();
buffer.append(source.get("fname") + ", ");
buffer.append(source.get("lname") + ", ");
buffer.append(source.get("city") + ", ");
buffer.append(source.get("street") + ", ");
buffer.append(source.get("zip") + ", ");
buffer.append(source.get("state") + ", ");
return (S) buffer.toString();
return (S) ((source.get("fname") + ", ")
+ source.get("lname") + ", "
+ source.get("city") + ", "
+ source.get("street") + ", "
+ source.get("zip") + ", "
+ source.get("state") + ", ");
}
}

View File

@@ -1,29 +0,0 @@
WebSockets Sample
==============
This example demonstrates the Standard WebSocket protocol (without any sub-protocols) with Spring Integration Adapters.
It just sends current time from the server to all connected clients.
## Server
The server is presented only with a single `org.springframework.integration.samples.websocket.standard.server.Application`
class, which is based on the Spring Boot AutoConfiguration and Spring Integration Java & Annotation configuration.
It is a `main` and starts an embedded Tomcat server on the default `8080` port. The WebSocket endpoint is mapped to the `/time` path.
The server also can be run from Gradle `gradlew :web-sockets:run`
## Java Client
The `org.springframework.integration.samples.websocket.standard.client.Application` is a simple Java application,
which starts an integration flow (`client-context.xml`), connects to the WebSocket server and prints `Message`s to the
logs, which are received over WebSocket.
## Browser Client
The `index.html` in the `src/main/resources/static` directory of this project demonstrates a JavaScript `SockJS` client, which connects
to our server and just prints its messages in the middle of page.
## Test Case
The `org.springframework.integration.samples.websocket.standard.ApplicationTests` demonstrates the Spring Boot test
framework and starts Server & Client to check, that the client receives correct data.

View File

@@ -1,123 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>1.1.6.RELEASE</version>
</parent>
<groupId>org.springframework.integration.samples</groupId>
<artifactId>web-sockets</artifactId>
<version>3.0.0.BUILD-SNAPSHOT</version>
<name>Web Sockets Basic Sample</name>
<description>Web Sockets Basic Sample</description>
<url>http://projects.spring.io/spring-integration</url>
<organization>
<name>SpringIO</name>
<url>https://spring.io</url>
</organization>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>garyrussell</id>
<name>Gary Russell</name>
<email>grussell@pivotal.io</email>
<roles>
<role>project lead</role>
</roles>
</developer>
<developer>
<id>markfisher</id>
<name>Mark Fisher</name>
<email>mfisher@pivotal.io</email>
<roles>
<role>project founder and lead emeritus</role>
</roles>
</developer>
<developer>
<id>ghillert</id>
<name>Gunnar Hillert</name>
<email>ghillert@pivotal.io</email>
</developer>
<developer>
<id>abilan</id>
<name>Artem Bilan</name>
<email>abilan@pivotal.io</email>
</developer>
</developers>
<scm>
<connection>scm:git:scm:git:git://github.com/spring-projects/spring-integration-samples.git</connection>
<developerConnection>scm:git:scm:git:ssh://git@github.com:spring-projects/spring-integration-samples.git</developerConnection>
<url>https://github.com/spring-projects/spring-integration-samples</url>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>repo.spring.io.milestone</id>
<name>Spring Framework Maven Milestone Repository</name>
<url>https://repo.spring.io/libs-milestone</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.0.7.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-websocket</artifactId>
<version>4.1.0.BUILD-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,34 +0,0 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed 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.springframework.integration.samples.websocket.standard.client;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Artem Bilan
* @since 3.0
*/
public class Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("client-context.xml", Application.class);
System.in.read();
ctx.close();
}
}

View File

@@ -1,142 +0,0 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed 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.springframework.integration.samples.websocket.standard.server;
import java.text.DateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.concurrent.Executors;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.annotation.Poller;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.annotation.Transformer;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.ExecutorChannel;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.handler.LoggingHandler;
import org.springframework.integration.splitter.DefaultMessageSplitter;
import org.springframework.integration.transformer.AbstractPayloadTransformer;
import org.springframework.integration.transformer.HeaderEnricher;
import org.springframework.integration.transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor;
import org.springframework.integration.websocket.ServerWebSocketContainer;
import org.springframework.integration.websocket.outbound.WebSocketOutboundMessageHandler;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.support.GenericMessage;
/**
* @author Artem Bilan
* @since 3.0
*/
@Configuration
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
System.out.println("Hit 'Enter' to terminate");
System.in.read();
ctx.close();
}
@Bean
public ServerWebSocketContainer serverWebSocketContainer() {
return new ServerWebSocketContainer("/time").withSockJs();
}
@Bean
@InboundChannelAdapter(value = "splitChannel", poller = @Poller(fixedDelay = "1000", maxMessagesPerPoll = "1"))
public MessageSource<?> webSocketSessionsMessageSource() {
return new MessageSource<Iterator<String>>() {
@Override
public Message<Iterator<String>> receive() {
return new GenericMessage<Iterator<String>>(serverWebSocketContainer().getSessions().keySet().iterator());
}
};
}
@Bean
public MessageChannel splitChannel() {
return new DirectChannel();
}
@Bean
@ServiceActivator(inputChannel = "splitChannel")
public MessageHandler splitter() {
DefaultMessageSplitter splitter = new DefaultMessageSplitter();
splitter.setOutputChannelName("headerEnricherChannel");
return splitter;
}
@Bean
public MessageChannel headerEnricherChannel() {
return new ExecutorChannel(Executors.newCachedThreadPool());
}
@Bean
@Transformer(inputChannel = "headerEnricherChannel", outputChannel = "transformChannel")
public HeaderEnricher headerEnricher() {
return new HeaderEnricher(Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER,
new ExpressionEvaluatingHeaderValueMessageProcessor<Object>("payload", null)));
}
@Bean
@Transformer(inputChannel = "transformChannel", outputChannel = "sendTimeChannel")
public AbstractPayloadTransformer<?, ?> transformer() {
return new AbstractPayloadTransformer<Object, Object>() {
@Override
protected Object transformPayload(Object payload) throws Exception {
return DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.DEFAULT).format(new Date());
}
};
}
@Bean
public MessageChannel sendTimeChannel() {
return new PublishSubscribeChannel();
}
@Bean
@ServiceActivator(inputChannel = "sendTimeChannel")
public MessageHandler webSocketOutboundAdapter() {
return new WebSocketOutboundMessageHandler(serverWebSocketContainer());
}
@Bean
@ServiceActivator(inputChannel = "sendTimeChannel")
public MessageHandler loggingChannelAdapter() {
LoggingHandler loggingHandler = new LoggingHandler("info");
loggingHandler.setExpression("'The time ' + payload + ' has been sent to the WebSocketSession ' + headers.simpSessionId");
return loggingHandler;
}
}

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-websocket="http://www.springframework.org/schema/integration/websocket"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/integration/websocket
http://www.springframework.org/schema/integration/websocket/spring-integration-websocket.xsd">
<bean id="webSocketClient" class="org.springframework.web.socket.client.standard.StandardWebSocketClient"/>
<int-websocket:client-container id="clientWebSocketContainer"
client="webSocketClient"
uri="ws://localhost:8080/time/websocket"/>
<int-websocket:inbound-channel-adapter container="clientWebSocketContainer"
channel="webSocketInputChannel"/>
<int:logging-channel-adapter id="webSocketInputChannel"/>
</beans>

View File

@@ -1,34 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Time over WebSocket</title>
<script src="http://localhost:8080/sockjs.js"></script>
<script type="text/javascript">
var sock = new SockJS('http://localhost:8080/time');
sock.onopen = function () {
document.getElementById('time').innerHTML = 'Connecting...';
};
sock.onmessage = function (e) {
document.getElementById('time').innerHTML = e.data;
};
sock.onclose = function () {
document.getElementById('time').innerHTML = "Server closed connection or hasn't been started";
};
</script>
</head>
<body style="margin: 0">
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript!
WebSocket relies on Javascript being enabled. Please enable Javascript and reload this page!</h2></noscript>
<div id="time"
style="position: absolute;
bottom: 0;
font-size: 800%;
height: 200px;
margin: auto;
text-align: center;
top: 0;
width: 100%;">Starting...</div>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -1,85 +0,0 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed 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.springframework.integration.samples.websocket.standard;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.samples.websocket.standard.server.Application;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
/**
* @author Artem Bilan
* @since 3.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
public class ApplicationTests {
@Test
public void testWebSockets() throws InterruptedException {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("client-context.xml",
org.springframework.integration.samples.websocket.standard.client.Application.class);
DirectChannel webSocketInputChannel = ctx.getBean("webSocketInputChannel", DirectChannel.class);
final CountDownLatch stopLatch = new CountDownLatch(2);
webSocketInputChannel.addInterceptor(new ChannelInterceptorAdapter() {
@Override
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
Object payload = message.getPayload();
assertThat(payload, instanceOf(String.class));
Date date = null;
try {
date = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.DEFAULT).parse((String) payload);
}
catch (ParseException e) {
fail("fail to parse date");
}
assertThat(new Date().compareTo(date), greaterThanOrEqualTo(0));
stopLatch.countDown();
}
});
assertTrue(stopLatch.await(10, TimeUnit.SECONDS));
ctx.close();
}
}

View File

@@ -192,7 +192,6 @@ subprojects { subproject ->
subethasmtpVersion = '1.2'
slf4jVersion = '1.7.6'
springIntegrationVersion = '4.0.4.RELEASE'
springIntegration41Version = '4.1.0.BUILD-SNAPSHOT'
springIntegrationDslVersion = '1.0.0.M3'
springVersion = '4.0.7.RELEASE'
springSecurityVersion = '3.2.4.RELEASE'
@@ -520,8 +519,8 @@ project('si4demo') {
dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-integration'
compile "org.springframework.integration:spring-integration-mail:$springIntegration41Version"
compile "org.springframework.integration:spring-integration-twitter:$springIntegration41Version"
compile "org.springframework.integration:spring-integration-mail"
compile "org.springframework.integration:spring-integration-twitter"
compile "org.springframework.integration:spring-integration-java-dsl:$springIntegrationDslVersion"
compile "javax.mail:javax.mail-api:$javaxMailVersion"
compile "com.sun.mail:javax.mail:$javaxMailVersion"
@@ -550,7 +549,7 @@ project('cafe-dsl') {
dependencies {
compile project(":cafe-si")
compile 'org.springframework.boot:spring-boot-starter-integration'
compile "org.springframework.integration:spring-integration-core:$springIntegration41Version"
compile "org.springframework.integration:spring-integration-core"
compile "org.springframework.integration:spring-integration-java-dsl:$springIntegrationDslVersion"
testCompile 'org.springframework.boot:spring-boot-starter-test'
@@ -637,7 +636,6 @@ project('mail') {
dependencies {
compile "org.springframework.integration:spring-integration-mail:$springIntegrationVersion"
compile "org.springframework:spring-context:$springVersion"
compile "javax.mail:javax.mail-api:$javaxMailVersion"
compile "com.sun.mail:mailapi:$javaxMailVersion"
}
@@ -819,17 +817,6 @@ project('xmpp') {
}
}
project('async-gateway') {
description = 'Async Gateway Sample'
sourceCompatibility = 1.8
dependencies {
compile "org.springframework.integration:spring-integration-core:$springIntegration41Version"
compile "org.projectreactor.spring:reactor-spring-context:$reactorSpringVersion"
}
}
project('dynamic-poller') {
description = 'Dynamic Poller Sample'
@@ -923,7 +910,6 @@ project('rest-http') {
compile "org.springframework:spring-oxm:$springVersion"
compile "org.springframework:spring-tx:$springVersion"
compile "org.springframework:spring-jdbc:$springVersion"
compile "org.springframework:spring-context:$springVersion"
compile "org.springframework:spring-aop:$springVersion"
compile "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
compile "org.springframework.security:spring-security-web:$springSecurityVersion"
@@ -1097,46 +1083,6 @@ project('tx-synch') {
}
}
project('web-sockets') {
description = 'Web Sockets Basic Sample'
apply plugin: 'spring-boot'
dependencies {
compile 'org.springframework.boot:spring-boot-starter-websocket'
compile "org.springframework.integration:spring-integration-websocket:$springIntegration41Version"
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
mainClassName = 'org.springframework.integration.samples.websocket.standard.server.Application'
tasks.withType(JavaExec) {
standardInput = System.in
}
}
project('stomp-chat') {
description = 'Web Sockets Stomp Chat Sample'
apply plugin: 'spring-boot'
dependencies {
compile 'org.springframework.boot:spring-boot-starter-websocket'
compile "org.springframework.integration:spring-integration-websocket:$springIntegration41Version"
compile "org.springframework.integration:spring-integration-event:$springIntegration41Version"
compile "org.springframework.integration:spring-integration-groovy:$springIntegration41Version"
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
mainClassName = 'org.springframework.integration.samples.chat.stomp.server.Application'
tasks.withType(JavaExec) {
standardInput = System.in
}
}
task wrapper(type: Wrapper) {
description = 'Generates gradlew[.bat] scripts'
gradleVersion = '1.12'

View File

@@ -1,2 +1,2 @@
version=3.0.0.BUILD-SNAPSHOT
springBootVersion=1.1.7.RELEASE
springBootVersion=1.1.8.RELEASE

View File

@@ -1 +0,0 @@
/bin/

View File

@@ -1,33 +0,0 @@
Async Gateway Sample
====================
Gateways provide a convenient way to expose a Proxy over a service-interface thus giving you POJO-based access to a messaging system (based on objects in your own domain, or primitives/Strings, etc). However, when you invoke a method, you expect the method to return. A gateway's method call represents a contract with the messaging system, which states that for each request, there will always be a reply. Therefore you must always guarantee that your message flow is in compliance with such a contract.
But what about the cases where you can't (e.g, message was filtered out and discarded or routed into a unidirectional sub-flow)?
Starting with Spring Integration 2.0, we introduced support for an Asynchronous Gateway, which is a convenient way to initiate flows, where you may not know, if a reply is expected or how long will it take for it to arrive. A natural way to handle these types of scenarios in Java would be to rely upon **java.util.concurrent.Future** instances. That is exactly what Spring Integration uses to support Asynchronous Gateways.
This example demonstrates how you can apply an Asynchronous Gateway based on the following simple use case:
We are sending a request to a **MathService** to multiply random numbers by 2. As you can see from the configuration there is a filter that discards any request for the number that is less then a 100. This means that there will be no replies coming for the requests with numbers less then 100. Typically, when using the regular Gateway, the gateway method would lock until a timeout occurs. In this example, however, the responses are coming back right away as Java Futures which we evaluate.
To run this sample, simply execute **org.springframework.integration.samples.async.gateway.AsyncGatewayTest**.
You should see the following output:
INFO : org.springframework.integration.samples.async.gateway.AsyncGatewayTest - Result of multiplication of 107 by 2 is 214
INFO : org.springframework.integration.samples.async.gateway.AsyncGatewayTest - Result of multiplication of 146 by 2 is 292
INFO : org.springframework.integration.samples.async.gateway.AsyncGatewayTest - Result of multiplication of 189 by 2 is 378
INFO : org.springframework.integration.samples.async.gateway.AsyncGatewayTest - Result of multiplication of 130 by 2 is 260
. . . . .
INFO : org.springframework.integration.samples.async.gateway.AsyncGatewayTest - Multiplication of 38 by 2 is can not be accomplished in 20 seconds
INFO : org.springframework.integration.samples.async.gateway.AsyncGatewayTest - Multiplication of 39 by 2 is can not be accomplished in 20 seconds
INFO : org.springframework.integration.samples.async.gateway.AsyncGatewayTest - Multiplication of 36 by 2 is can not be accomplished in 20 seconds
INFO : org.springframework.integration.samples.async.gateway.AsyncGatewayTest - Multiplication of 37 by 2 is can not be accomplished in 20 seconds
Spring Integration 4.0 provided the capability to more easily configure Messaging Gateways with Java configuration.
Spring Integration 4.1 added support for **ListenableFuture** and **Promise** (from project reactor) return types.
The **ListenableFutureTest** and **PromiseTest** test classes replicate the above test case, using those return types, and showing the use of **@MessagingGateway** java configuration.

View File

@@ -1,106 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.integration.samples</groupId>
<artifactId>async-gateway</artifactId>
<version>3.0.0.BUILD-SNAPSHOT</version>
<name>Async Gateway Sample</name>
<description>Async Gateway Sample</description>
<url>http://projects.spring.io/spring-integration</url>
<organization>
<name>SpringIO</name>
<url>https://spring.io</url>
</organization>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>garyrussell</id>
<name>Gary Russell</name>
<email>grussell@pivotal.io</email>
<roles>
<role>project lead</role>
</roles>
</developer>
<developer>
<id>markfisher</id>
<name>Mark Fisher</name>
<email>mfisher@pivotal.io</email>
<roles>
<role>project founder and lead emeritus</role>
</roles>
</developer>
<developer>
<id>ghillert</id>
<name>Gunnar Hillert</name>
<email>ghillert@pivotal.io</email>
</developer>
<developer>
<id>abilan</id>
<name>Artem Bilan</name>
<email>abilan@pivotal.io</email>
</developer>
</developers>
<scm>
<connection>scm:git:scm:git:git://github.com/spring-projects/spring-integration-samples.git</connection>
<developerConnection>scm:git:scm:git:ssh://git@github.com:spring-projects/spring-integration-samples.git</developerConnection>
<url>https://github.com/spring-projects/spring-integration-samples</url>
</scm>
<repositories>
<repository>
<id>repo.spring.io.milestone</id>
<name>Spring Framework Maven Milestone Repository</name>
<url>https://repo.spring.io/libs-milestone</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.projectreactor.spring</groupId>
<artifactId>reactor-spring-context</artifactId>
<version>1.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.0.7.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>4.1.0.BUILD-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,32 +0,0 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed 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.springframework.integration.samples.async.gateway;
import java.util.Random;
/**
* @author Oleg Zhurakousky
*
*/
public class MathService {
private final Random random = new Random();
public int multiplyByTwo(int i) throws Exception{
long sleep = random.nextInt(10) * 500;
Thread.sleep(sleep);
return i*2;
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed 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.springframework.integration.samples.async.gateway;
import java.util.concurrent.Future;
/**
* @author Oleg Zhurakousky
*
*/
public interface MathServiceGateway {
Future<Integer> multiplyByTwo(int i);
}

View File

@@ -1,39 +0,0 @@
##
# Dispatcher configuration
#
# Each dispatcher must be configured with a type:
#
# reactor.dispatchers.<name>.type = <type>
#
# Legal values for <type> are eventLoop, ringBuffer, synchronous, and threadPoolExecutor.
# Depending on the type, further configuration is be possible:
#
# reactor.dispatchers.<name>.size: eventLoop and threadPoolExecutor Dispatchers
# reactor.dispatchers.<name>.backlog: eventLoop, ringBuffer, and threadPoolExecutor Dispatchers
#
# A size less than 1 may be specified to indicate that the size should be the same as the number
# of CPUs.
# A thread pool executor dispatcher, named threadPoolExecutor
reactor.dispatchers.threadPoolExecutor.type = threadPoolExecutor
reactor.dispatchers.threadPoolExecutor.size = 100
# Backlog is how many Task objects to warm up internally
reactor.dispatchers.threadPoolExecutor.backlog = 100
# An event loop dispatcher, named eventLoop
reactor.dispatchers.eventLoop.type =
reactor.dispatchers.eventLoop.size = 0
reactor.dispatchers.eventLoop.backlog = 2048
# A ring buffer dispatcher, named ringBuffer
reactor.dispatchers.ringBuffer.type =
reactor.dispatchers.ringBuffer.backlog = 2048
# A work queue dispatcher, named workQueue
reactor.dispatchers.workQueue.type =
reactor.dispatchers.workQueue.size = 0
reactor.dispatchers.workQueue.backlog = 2048
# The dispatcher named ringBuffer should be the default dispatcher
reactor.dispatchers.default = threadPoolExecutor

View File

@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:task="http://www.springframework.org/schema/task">
<int:gateway id="mathService"
service-interface="org.springframework.integration.samples.async.gateway.MathServiceGateway"
default-request-channel="requestChannel"
async-executor="executor" default-reply-timeout="0"/>
<int:channel id="requestChannel" />
<int:filter input-channel="requestChannel" output-channel="calculatingChannel" expression="payload gt 100" />
<int:channel id="calculatingChannel" />
<int:service-activator input-channel="calculatingChannel">
<bean class="org.springframework.integration.samples.async.gateway.MathService"/>
</int:service-activator>
<task:executor id="executor" pool-size="100" />
</beans>

View File

@@ -1,90 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed 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.springframework.integration.samples.async.gateway;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* @author Oleg Zhurakousky
* @author Gary Russell
*
*/
public class AsyncGatewayTest {
private static Logger logger = Logger.getLogger(AsyncGatewayTest.class);
private static ExecutorService executor = Executors.newFixedThreadPool(100);
private static int timeout = 20;
@Test
public void testAsyncGateway() throws Exception{
ConfigurableApplicationContext ac =
new FileSystemXmlApplicationContext("src/main/resources/META-INF/spring/integration/*.xml");
MathServiceGateway mathService = ac.getBean("mathService", MathServiceGateway.class);
Map<Integer, Future<Integer>> results = new HashMap<Integer, Future<Integer>>();
Random random = new Random();
for (int i = 0; i < 100; i++) {
int number = random.nextInt(200);
Future<Integer> result = mathService.multiplyByTwo(number);
results.put(number, result);
}
for (final Map.Entry<Integer, Future<Integer>> resultEntry : results.entrySet()) {
executor.execute(() -> {
int[] result = processFuture(resultEntry);
if (result[1] == -1){
logger.info("Multiplying " + result[0] + " should be easy. You should be able to multiply any number < 100 by 2 in your head");
} else if (result[1] == -2){
logger.info("Multiplication of " + result[0] + " by 2 is can not be accomplished in " + timeout + " seconds");
} else {
logger.info("Result of multiplication of " + result[0] + " by 2 is " + result[1]);
}
});
}
executor.shutdown();
executor.awaitTermination(60, TimeUnit.SECONDS);
logger.info("Finished");
ac.close();
}
public static int[] processFuture(Map.Entry<Integer, Future<Integer>> resultEntry){
int originalNumber = resultEntry.getKey();
Future<Integer> result = resultEntry.getValue();
try {
int finalResult = result.get(timeout, TimeUnit.SECONDS);
return new int[]{originalNumber, finalResult};
} catch (ExecutionException e) {
return new int[]{originalNumber, -1};
} catch (TimeoutException tex){
return new int[]{originalNumber, -2};
} catch (Exception ex){
System.out.println();
// ignore
}
return null;
}
}

View File

@@ -1,148 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed 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.springframework.integration.samples.async.gateway;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.integration.annotation.Filter;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.messaging.MessageChannel;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
/**
* @author Oleg Zhurakousky
* @author Gary Russell
*
*/
@ContextConfiguration(classes = ListenableFutureTest.TestConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class ListenableFutureTest {
private static Logger logger = Logger.getLogger(ListenableFutureTest.class);
@Autowired
private MathGateway gateway;
@Test
public void testAsyncGateway() throws Exception{
Random random = new Random();
int[] numbers = new int[100];
int expectedResults = 0;
for (int i = 0; i < 100; i++) {
numbers[i] = random.nextInt(200);
if (numbers[i] > 100) {
expectedResults++;
}
}
final CountDownLatch latch = new CountDownLatch(expectedResults);
final AtomicInteger failures = new AtomicInteger();
for (int i = 0; i < 100; i++) {
final int number = numbers[i];
ListenableFuture<Integer> result = gateway.multiplyByTwo(number);
ListenableFutureCallback<Integer> callback = new ListenableFutureCallback<Integer>() {
@Override
public void onSuccess(Integer result) {
logger.info("Result of multiplication of " + number + " by 2 is " + result);
latch.countDown();
}
@Override
public void onFailure(Throwable t) {
failures.incrementAndGet();
logger.error("Unexpected exception for " + number, t);
latch.countDown();
}
};
result.addCallback(callback);
}
assertTrue(latch.await(60, TimeUnit.SECONDS));
assertEquals(0, failures.get());
logger.info("Finished");
}
@Configuration
@ComponentScan
@EnableIntegration
@IntegrationComponentScan
public static class TestConfig {
@Bean
public MessageChannel gatewayChannel() {
return new DirectChannel();
}
@Bean
@ServiceActivator(inputChannel="mathServiceChannel")
public MathService mathService() {
return new MathService();
}
@Bean
public AsyncTaskExecutor exec() {
SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
simpleAsyncTaskExecutor.setThreadNamePrefix("exec-");
return simpleAsyncTaskExecutor;
}
}
@MessagingGateway(defaultReplyTimeout = 0)
public interface MathGateway {
@Gateway(requestChannel = "gatewayChannel")
ListenableFuture<Integer> multiplyByTwo(int number);
}
@MessageEndpoint
public static class Gt100Filter {
@Filter(inputChannel="gatewayChannel", outputChannel="mathServiceChannel")
public boolean filter(int i) {
return i > 100;
}
}
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed 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.springframework.integration.samples.async.gateway;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import reactor.core.composable.Promise;
import reactor.spring.context.config.EnableReactor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.integration.annotation.Filter;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.messaging.MessageChannel;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Oleg Zhurakousky
* @author Gary Russell
*
*/
@ContextConfiguration(classes = PromiseTest.TestConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class PromiseTest {
private static Logger logger = Logger.getLogger(PromiseTest.class);
@Autowired
private MathGateway gateway;
@Test
public void testPromiseGateway() throws Exception {
Random random = new Random();
int[] numbers = new int[100];
int expectedResults = 0;
for (int i = 0; i < 100; i++) {
numbers[i] = random.nextInt(200);
if (numbers[i] > 100) {
expectedResults++;
}
}
final CountDownLatch latch = new CountDownLatch(expectedResults);
final AtomicInteger failures = new AtomicInteger();
for (int i = 0; i < 100; i++) {
final int number = numbers[i];
gateway.multiplyByTwo(number)
.onSuccess(result1 -> {
logger.info("Result of multiplication of " + number + " by 2 is " + result1);
latch.countDown();
})
.onError(t -> {
failures.incrementAndGet();
logger.error("Unexpected exception for " + number, t);
latch.countDown();
})
.flush();
}
assertTrue(latch.await(60, TimeUnit.SECONDS));
assertEquals(0, failures.get());
logger.info("Finished");
}
@Configuration
@EnableIntegration
@EnableReactor
@ComponentScan
@IntegrationComponentScan
public static class TestConfig {
@Bean
public MessageChannel gatewayChannel() {
return new DirectChannel();
}
@Bean
@ServiceActivator(inputChannel = "mathServiceChannel")
public MathService mathService() {
return new MathService();
}
@Bean
public AsyncTaskExecutor exec() {
SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
simpleAsyncTaskExecutor.setThreadNamePrefix("exec-");
return simpleAsyncTaskExecutor;
}
}
@MessagingGateway(defaultReplyTimeout = 0, reactorEnvironment = "reactorEnv")
public interface MathGateway {
@Gateway(requestChannel = "gatewayChannel")
Promise<Integer> multiplyByTwo(int number);
}
@MessageEndpoint
public static class Gt100Filter {
@Filter(inputChannel = "gatewayChannel", outputChannel = "mathServiceChannel")
public boolean filter(int i) {
return i > 100;
}
}
}

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss.SSS} %-5p [%t][%c] %m%n" />
</layout>
</appender>
<logger name="org.springframework.integration">
<level value="warn" />
</logger>
<logger name="org.springframework.integration.samples.async.gateway">
<level value="debug" />
</logger>
<!-- Root Logger -->
<root>
<priority value="warn" />
<appender-ref ref="console" />
</root>
</log4j:configuration>