Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
bc7004d9
Commit
bc7004d9
authored
Jun 15, 2021
by
Andy Wilkinson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix WebSocket support with Jetty 10.0.x
Fixes gh-26847
parent
d635e1e7
Changes
31
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
2135 additions
and
1 deletion
+2135
-1
Jetty10WebSocketServletWebServerCustomizer.java
...t/servlet/Jetty10WebSocketServletWebServerCustomizer.java
+110
-0
WebSocketServletAutoConfiguration.java
.../websocket/servlet/WebSocketServletAutoConfiguration.java
+14
-1
build.gradle
...t-smoke-tests/spring-boot-smoke-test-jetty10/build.gradle
+19
-0
ExampleServletContextListener.java
...n/java/smoketest/jetty/ExampleServletContextListener.java
+40
-0
SampleJetty10Application.java
...c/main/java/smoketest/jetty/SampleJetty10Application.java
+29
-0
HelloWorldService.java
.../main/java/smoketest/jetty/service/HelloWorldService.java
+32
-0
SampleController.java
...0/src/main/java/smoketest/jetty/web/SampleController.java
+38
-0
application.properties
...ke-test-jetty10/src/main/resources/application.properties
+3
-0
SampleJetty10ApplicationTests.java
...t/java/smoketest/jetty/SampleJetty10ApplicationTests.java
+72
-0
build.gradle
...sts/spring-boot-smoke-test-websocket-jetty10/build.gradle
+22
-0
SampleJetty10WebSocketsApplication.java
...t/websocket/jetty/SampleJetty10WebSocketsApplication.java
+90
-0
GreetingService.java
...ava/smoketest/websocket/jetty/client/GreetingService.java
+23
-0
SimpleClientWebSocketHandler.java
.../websocket/jetty/client/SimpleClientWebSocketHandler.java
+60
-0
SimpleGreetingService.java
...oketest/websocket/jetty/client/SimpleGreetingService.java
+26
-0
DefaultEchoService.java
...va/smoketest/websocket/jetty/echo/DefaultEchoService.java
+32
-0
EchoService.java
...main/java/smoketest/websocket/jetty/echo/EchoService.java
+23
-0
EchoWebSocketHandler.java
.../smoketest/websocket/jetty/echo/EchoWebSocketHandler.java
+58
-0
ReverseWebSocketEndpoint.java
...est/websocket/jetty/reverse/ReverseWebSocketEndpoint.java
+33
-0
Direction.java
.../main/java/smoketest/websocket/jetty/snake/Direction.java
+23
-0
Location.java
...c/main/java/smoketest/websocket/jetty/snake/Location.java
+78
-0
Snake.java
.../src/main/java/smoketest/websocket/jetty/snake/Snake.java
+156
-0
SnakeTimer.java
...main/java/smoketest/websocket/jetty/snake/SnakeTimer.java
+117
-0
SnakeUtils.java
...main/java/smoketest/websocket/jetty/snake/SnakeUtils.java
+66
-0
SnakeWebSocketHandler.java
...moketest/websocket/jetty/snake/SnakeWebSocketHandler.java
+103
-0
echo.html
...est-websocket-jetty10/src/main/resources/static/echo.html
+134
-0
index.html
...st-websocket-jetty10/src/main/resources/static/index.html
+33
-0
reverse.html
...-websocket-jetty10/src/main/resources/static/reverse.html
+141
-0
snake.html
...st-websocket-jetty10/src/main/resources/static/snake.html
+250
-0
SampleJetty10WebSocketsApplicationTests.java
...socket/jetty/SampleJetty10WebSocketsApplicationTests.java
+128
-0
CustomContainerWebSocketsApplicationTests.java
...jetty/echo/CustomContainerWebSocketsApplicationTests.java
+142
-0
SnakeTimerTests.java
...java/smoketest/websocket/jetty/snake/SnakeTimerTests.java
+40
-0
No files found.
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/servlet/Jetty10WebSocketServletWebServerCustomizer.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
.
boot
.
autoconfigure
.
websocket
.
servlet
;
import
java.lang.reflect.Method
;
import
javax.servlet.ServletContext
;
import
org.eclipse.jetty.server.Server
;
import
org.eclipse.jetty.webapp.AbstractConfiguration
;
import
org.eclipse.jetty.webapp.WebAppContext
;
import
org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory
;
import
org.springframework.boot.web.server.WebServerFactoryCustomizer
;
import
org.springframework.core.Ordered
;
import
org.springframework.util.ClassUtils
;
import
org.springframework.util.ReflectionUtils
;
/**
* WebSocket customizer for {@link JettyServletWebServerFactory} with Jetty 10.
*
* @author Andy Wilkinson
*/
class
Jetty10WebSocketServletWebServerCustomizer
implements
WebServerFactoryCustomizer
<
JettyServletWebServerFactory
>,
Ordered
{
static
final
String
JETTY_WEB_SOCKET_SERVER_CONTAINER
=
"org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer"
;
static
final
String
JAVAX_WEB_SOCKET_SERVER_CONTAINER
=
"org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketServerContainer"
;
@Override
public
void
customize
(
JettyServletWebServerFactory
factory
)
{
factory
.
addConfigurations
(
new
AbstractConfiguration
()
{
@Override
public
void
configure
(
WebAppContext
context
)
throws
Exception
{
ServletContext
servletContext
=
context
.
getServletContext
();
Class
<?>
jettyContainer
=
ClassUtils
.
forName
(
JETTY_WEB_SOCKET_SERVER_CONTAINER
,
null
);
Method
getJettyContainer
=
ReflectionUtils
.
findMethod
(
jettyContainer
,
"getContainer"
,
ServletContext
.
class
);
Server
server
=
context
.
getServer
();
if
(
ReflectionUtils
.
invokeMethod
(
getJettyContainer
,
null
,
servletContext
)
==
null
)
{
ensureWebSocketComponents
(
server
,
servletContext
);
ensureContainer
(
jettyContainer
,
servletContext
);
}
Class
<?>
javaxContainer
=
ClassUtils
.
forName
(
JAVAX_WEB_SOCKET_SERVER_CONTAINER
,
null
);
Method
getJavaxContainer
=
ReflectionUtils
.
findMethod
(
javaxContainer
,
"getContainer"
,
ServletContext
.
class
);
if
(
ReflectionUtils
.
invokeMethod
(
getJavaxContainer
,
"getContainer"
,
servletContext
)
==
null
)
{
ensureWebSocketComponents
(
server
,
servletContext
);
ensureUpgradeFilter
(
servletContext
);
ensureMappings
(
servletContext
);
ensureContainer
(
javaxContainer
,
servletContext
);
}
}
private
void
ensureWebSocketComponents
(
Server
server
,
ServletContext
servletContext
)
throws
ClassNotFoundException
{
Class
<?>
webSocketServerComponents
=
ClassUtils
.
forName
(
"org.eclipse.jetty.websocket.core.server.WebSocketServerComponents"
,
null
);
Method
ensureWebSocketComponents
=
ReflectionUtils
.
findMethod
(
webSocketServerComponents
,
"ensureWebSocketComponents"
,
Server
.
class
,
ServletContext
.
class
);
ReflectionUtils
.
invokeMethod
(
ensureWebSocketComponents
,
null
,
server
,
servletContext
);
}
private
void
ensureContainer
(
Class
<?>
container
,
ServletContext
servletContext
)
throws
ClassNotFoundException
{
Method
ensureContainer
=
ReflectionUtils
.
findMethod
(
container
,
"ensureContainer"
,
ServletContext
.
class
);
ReflectionUtils
.
invokeMethod
(
ensureContainer
,
null
,
servletContext
);
}
private
void
ensureUpgradeFilter
(
ServletContext
servletContext
)
throws
ClassNotFoundException
{
Class
<?>
webSocketUpgradeFilter
=
ClassUtils
.
forName
(
"org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter"
,
null
);
Method
ensureFilter
=
ReflectionUtils
.
findMethod
(
webSocketUpgradeFilter
,
"ensureFilter"
,
ServletContext
.
class
);
ReflectionUtils
.
invokeMethod
(
ensureFilter
,
null
,
servletContext
);
}
private
void
ensureMappings
(
ServletContext
servletContext
)
throws
ClassNotFoundException
{
Class
<?>
webSocketMappings
=
ClassUtils
.
forName
(
"org.eclipse.jetty.websocket.core.server.WebSocketMappings"
,
null
);
Method
ensureMappings
=
ReflectionUtils
.
findMethod
(
webSocketMappings
,
"ensureMappings"
,
ServletContext
.
class
);
ReflectionUtils
.
invokeMethod
(
ensureMappings
,
null
,
servletContext
);
}
});
}
@Override
public
int
getOrder
()
{
return
0
;
}
}
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/servlet/WebSocketServletAutoConfiguration.java
View file @
bc7004d9
/*
/*
* Copyright 2012-20
19
the original author or authors.
* Copyright 2012-20
21
the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
...
@@ -83,6 +83,19 @@ public class WebSocketServletAutoConfiguration {
...
@@ -83,6 +83,19 @@ public class WebSocketServletAutoConfiguration {
}
}
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnClass
(
name
=
{
Jetty10WebSocketServletWebServerCustomizer
.
JAVAX_WEB_SOCKET_SERVER_CONTAINER
,
Jetty10WebSocketServletWebServerCustomizer
.
JETTY_WEB_SOCKET_SERVER_CONTAINER
})
static
class
Jetty10WebSocketConfiguration
{
@Bean
@ConditionalOnMissingBean
(
name
=
"websocketServletWebServerCustomizer"
)
Jetty10WebSocketServletWebServerCustomizer
websocketServletWebServerCustomizer
()
{
return
new
Jetty10WebSocketServletWebServerCustomizer
();
}
}
@Configuration
(
proxyBeanMethods
=
false
)
@Configuration
(
proxyBeanMethods
=
false
)
@ConditionalOnClass
(
io
.
undertow
.
websockets
.
jsr
.
Bootstrap
.
class
)
@ConditionalOnClass
(
io
.
undertow
.
websockets
.
jsr
.
Bootstrap
.
class
)
static
class
UndertowWebSocketConfiguration
{
static
class
UndertowWebSocketConfiguration
{
...
...
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jetty10/build.gradle
0 → 100644
View file @
bc7004d9
plugins
{
id
"java"
id
"org.springframework.boot.conventions"
}
description
=
"Spring Boot Jetty 10 smoke test"
dependencies
{
implementation
(
enforcedPlatform
(
"org.eclipse.jetty:jetty-bom:10.0.5"
))
implementation
(
project
(
":spring-boot-project:spring-boot-starters:spring-boot-starter-jetty"
))
{
exclude
group:
"org.eclipse.jetty.websocket"
,
module:
"websocket-server"
exclude
group:
"org.eclipse.jetty.websocket"
,
module:
"javax-websocket-server-impl"
}
implementation
(
project
(
":spring-boot-project:spring-boot-starters:spring-boot-starter-web"
))
{
exclude
module:
"spring-boot-starter-tomcat"
}
testImplementation
(
project
(
":spring-boot-project:spring-boot-starters:spring-boot-starter-test"
))
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jetty10/src/main/java/smoketest/jetty/ExampleServletContextListener.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
jetty10
;
import
javax.servlet.ServletContextEvent
;
import
javax.servlet.ServletContextListener
;
import
org.springframework.stereotype.Component
;
/**
* Simple {@link ServletContextListener} to test gh-2058.
*/
@Component
public
class
ExampleServletContextListener
implements
ServletContextListener
{
@Override
public
void
contextInitialized
(
ServletContextEvent
sce
)
{
System
.
out
.
println
(
"*** contextInitialized"
);
}
@Override
public
void
contextDestroyed
(
ServletContextEvent
sce
)
{
System
.
out
.
println
(
"*** contextDestroyed"
);
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jetty10/src/main/java/smoketest/jetty/SampleJetty10Application.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
jetty10
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
@SpringBootApplication
public
class
SampleJetty10Application
{
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
SampleJetty10Application
.
class
,
args
);
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jetty10/src/main/java/smoketest/jetty/service/HelloWorldService.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
jetty10
.
service
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
@Component
public
class
HelloWorldService
{
@Value
(
"${name:World}"
)
private
String
name
;
public
String
getHelloMessage
()
{
return
"Hello "
+
this
.
name
;
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jetty10/src/main/java/smoketest/jetty/web/SampleController.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
jetty10
.
web
;
import
smoketest.jetty10.service.HelloWorldService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
@Controller
public
class
SampleController
{
@Autowired
private
HelloWorldService
helloWorldService
;
@GetMapping
(
"/"
)
@ResponseBody
public
String
helloWorld
()
{
return
this
.
helloWorldService
.
getHelloMessage
();
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jetty10/src/main/resources/application.properties
0 → 100644
View file @
bc7004d9
server.compression.enabled
:
true
server.compression.min-response-size
:
1
server.jetty.threads.acceptors
=
2
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-jetty10/src/test/java/smoketest/jetty/SampleJetty10ApplicationTests.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
jetty10
;
import
java.io.ByteArrayInputStream
;
import
java.nio.charset.StandardCharsets
;
import
java.util.zip.GZIPInputStream
;
import
org.junit.jupiter.api.Test
;
import
org.junit.jupiter.api.condition.EnabledForJreRange
;
import
org.junit.jupiter.api.condition.JRE
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.boot.test.context.SpringBootTest.WebEnvironment
;
import
org.springframework.boot.test.web.client.TestRestTemplate
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.util.StreamUtils
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
/**
* Basic integration tests for demo application.
*
* @author Dave Syer
* @author Andy Wilkinson
*/
@EnabledForJreRange
(
min
=
JRE
.
JAVA_11
)
@SpringBootTest
(
webEnvironment
=
WebEnvironment
.
RANDOM_PORT
)
class
SampleJetty10ApplicationTests
{
@Autowired
private
TestRestTemplate
restTemplate
;
@Test
void
testHome
()
{
ResponseEntity
<
String
>
entity
=
this
.
restTemplate
.
getForEntity
(
"/"
,
String
.
class
);
assertThat
(
entity
.
getStatusCode
()).
isEqualTo
(
HttpStatus
.
OK
);
assertThat
(
entity
.
getBody
()).
isEqualTo
(
"Hello World"
);
}
@Test
void
testCompression
()
throws
Exception
{
HttpHeaders
requestHeaders
=
new
HttpHeaders
();
requestHeaders
.
set
(
"Accept-Encoding"
,
"gzip"
);
HttpEntity
<?>
requestEntity
=
new
HttpEntity
<>(
requestHeaders
);
ResponseEntity
<
byte
[]>
entity
=
this
.
restTemplate
.
exchange
(
"/"
,
HttpMethod
.
GET
,
requestEntity
,
byte
[].
class
);
assertThat
(
entity
.
getStatusCode
()).
isEqualTo
(
HttpStatus
.
OK
);
try
(
GZIPInputStream
inflater
=
new
GZIPInputStream
(
new
ByteArrayInputStream
(
entity
.
getBody
())))
{
assertThat
(
StreamUtils
.
copyToString
(
inflater
,
StandardCharsets
.
UTF_8
)).
isEqualTo
(
"Hello World"
);
}
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/build.gradle
0 → 100644
View file @
bc7004d9
plugins
{
id
"java"
id
"org.springframework.boot.conventions"
}
description
=
"Spring Boot WebSocket Jetty 10 smoke test"
dependencies
{
implementation
(
enforcedPlatform
(
"org.eclipse.jetty:jetty-bom:10.0.5"
))
implementation
(
project
(
":spring-boot-project:spring-boot-starters:spring-boot-starter-jetty"
))
{
exclude
group:
"org.eclipse.jetty.websocket"
,
module:
"websocket-server"
exclude
group:
"org.eclipse.jetty.websocket"
,
module:
"javax-websocket-server-impl"
}
implementation
(
project
(
":spring-boot-project:spring-boot-starters:spring-boot-starter-websocket"
))
{
exclude
module:
"spring-boot-starter-tomcat"
}
runtimeOnly
(
"org.eclipse.jetty.websocket:websocket-javax-server"
)
runtimeOnly
(
"org.eclipse.jetty.websocket:websocket-jetty-server"
)
testImplementation
(
project
(
":spring-boot-project:spring-boot-starters:spring-boot-starter-test"
))
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/SampleJetty10WebSocketsApplication.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
;
import
smoketest.websocket.jetty10.client.GreetingService
;
import
smoketest.websocket.jetty10.client.SimpleGreetingService
;
import
smoketest.websocket.jetty10.echo.DefaultEchoService
;
import
smoketest.websocket.jetty10.echo.EchoService
;
import
smoketest.websocket.jetty10.echo.EchoWebSocketHandler
;
import
smoketest.websocket.jetty10.reverse.ReverseWebSocketEndpoint
;
import
smoketest.websocket.jetty10.snake.SnakeWebSocketHandler
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.boot.web.servlet.support.SpringBootServletInitializer
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.socket.WebSocketHandler
;
import
org.springframework.web.socket.config.annotation.EnableWebSocket
;
import
org.springframework.web.socket.config.annotation.WebSocketConfigurer
;
import
org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry
;
import
org.springframework.web.socket.handler.PerConnectionWebSocketHandler
;
import
org.springframework.web.socket.server.standard.ServerEndpointExporter
;
@Configuration
(
proxyBeanMethods
=
false
)
@EnableAutoConfiguration
@EnableWebSocket
public
class
SampleJetty10WebSocketsApplication
extends
SpringBootServletInitializer
implements
WebSocketConfigurer
{
@Override
public
void
registerWebSocketHandlers
(
WebSocketHandlerRegistry
registry
)
{
registry
.
addHandler
(
echoWebSocketHandler
(),
"/echo"
).
withSockJS
();
registry
.
addHandler
(
snakeWebSocketHandler
(),
"/snake"
).
withSockJS
();
}
@Override
protected
SpringApplicationBuilder
configure
(
SpringApplicationBuilder
application
)
{
return
application
.
sources
(
SampleJetty10WebSocketsApplication
.
class
);
}
@Bean
public
EchoService
echoService
()
{
return
new
DefaultEchoService
(
"Did you say \"%s\"?"
);
}
@Bean
public
GreetingService
greetingService
()
{
return
new
SimpleGreetingService
();
}
@Bean
public
WebSocketHandler
echoWebSocketHandler
()
{
return
new
EchoWebSocketHandler
(
echoService
());
}
@Bean
public
WebSocketHandler
snakeWebSocketHandler
()
{
return
new
PerConnectionWebSocketHandler
(
SnakeWebSocketHandler
.
class
);
}
@Bean
public
ReverseWebSocketEndpoint
reverseWebSocketEndpoint
()
{
return
new
ReverseWebSocketEndpoint
();
}
@Bean
public
ServerEndpointExporter
serverEndpointExporter
()
{
return
new
ServerEndpointExporter
();
}
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
SampleJetty10WebSocketsApplication
.
class
,
args
);
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/client/GreetingService.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
client
;
public
interface
GreetingService
{
String
getGreeting
();
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/client/SimpleClientWebSocketHandler.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
client
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.atomic.AtomicReference
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.web.socket.TextMessage
;
import
org.springframework.web.socket.WebSocketSession
;
import
org.springframework.web.socket.handler.TextWebSocketHandler
;
public
class
SimpleClientWebSocketHandler
extends
TextWebSocketHandler
{
protected
Log
logger
=
LogFactory
.
getLog
(
SimpleClientWebSocketHandler
.
class
);
private
final
GreetingService
greetingService
;
private
final
CountDownLatch
latch
;
private
final
AtomicReference
<
String
>
messagePayload
;
public
SimpleClientWebSocketHandler
(
GreetingService
greetingService
,
CountDownLatch
latch
,
AtomicReference
<
String
>
message
)
{
this
.
greetingService
=
greetingService
;
this
.
latch
=
latch
;
this
.
messagePayload
=
message
;
}
@Override
public
void
afterConnectionEstablished
(
WebSocketSession
session
)
throws
Exception
{
TextMessage
message
=
new
TextMessage
(
this
.
greetingService
.
getGreeting
());
session
.
sendMessage
(
message
);
}
@Override
public
void
handleTextMessage
(
WebSocketSession
session
,
TextMessage
message
)
throws
Exception
{
this
.
logger
.
info
(
"Received: "
+
message
+
" ("
+
this
.
latch
.
getCount
()
+
")"
);
session
.
close
();
this
.
messagePayload
.
set
(
message
.
getPayload
());
this
.
latch
.
countDown
();
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/client/SimpleGreetingService.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
client
;
public
class
SimpleGreetingService
implements
GreetingService
{
@Override
public
String
getGreeting
()
{
return
"Hello world!"
;
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/echo/DefaultEchoService.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
echo
;
public
class
DefaultEchoService
implements
EchoService
{
private
final
String
echoFormat
;
public
DefaultEchoService
(
String
echoFormat
)
{
this
.
echoFormat
=
(
echoFormat
!=
null
)
?
echoFormat
:
"%s"
;
}
@Override
public
String
getMessage
(
String
message
)
{
return
String
.
format
(
this
.
echoFormat
,
message
);
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/echo/EchoService.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
echo
;
public
interface
EchoService
{
String
getMessage
(
String
message
);
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/echo/EchoWebSocketHandler.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
echo
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.web.socket.CloseStatus
;
import
org.springframework.web.socket.TextMessage
;
import
org.springframework.web.socket.WebSocketHandler
;
import
org.springframework.web.socket.WebSocketSession
;
import
org.springframework.web.socket.handler.TextWebSocketHandler
;
/**
* Echo messages by implementing a Spring {@link WebSocketHandler} abstraction.
*/
public
class
EchoWebSocketHandler
extends
TextWebSocketHandler
{
private
static
Log
logger
=
LogFactory
.
getLog
(
EchoWebSocketHandler
.
class
);
private
final
EchoService
echoService
;
public
EchoWebSocketHandler
(
EchoService
echoService
)
{
this
.
echoService
=
echoService
;
}
@Override
public
void
afterConnectionEstablished
(
WebSocketSession
session
)
{
logger
.
debug
(
"Opened new session in instance "
+
this
);
}
@Override
public
void
handleTextMessage
(
WebSocketSession
session
,
TextMessage
message
)
throws
Exception
{
String
echoMessage
=
this
.
echoService
.
getMessage
(
message
.
getPayload
());
logger
.
debug
(
echoMessage
);
session
.
sendMessage
(
new
TextMessage
(
echoMessage
));
}
@Override
public
void
handleTransportError
(
WebSocketSession
session
,
Throwable
exception
)
throws
Exception
{
session
.
close
(
CloseStatus
.
SERVER_ERROR
);
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/reverse/ReverseWebSocketEndpoint.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
reverse
;
import
java.io.IOException
;
import
javax.websocket.OnMessage
;
import
javax.websocket.Session
;
import
javax.websocket.server.ServerEndpoint
;
@ServerEndpoint
(
"/reverse"
)
public
class
ReverseWebSocketEndpoint
{
@OnMessage
public
void
handleMessage
(
Session
session
,
String
message
)
throws
IOException
{
session
.
getBasicRemote
().
sendText
(
"Reversed: "
+
new
StringBuilder
(
message
).
reverse
());
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/snake/Direction.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
snake
;
public
enum
Direction
{
NONE
,
NORTH
,
SOUTH
,
EAST
,
WEST
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/snake/Location.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
snake
;
public
class
Location
{
/**
* The X location.
*/
public
int
x
;
/**
* The Y location.
*/
public
int
y
;
public
Location
(
int
x
,
int
y
)
{
this
.
x
=
x
;
this
.
y
=
y
;
}
public
Location
getAdjacentLocation
(
Direction
direction
)
{
switch
(
direction
)
{
case
NORTH:
return
new
Location
(
this
.
x
,
this
.
y
-
SnakeUtils
.
GRID_SIZE
);
case
SOUTH:
return
new
Location
(
this
.
x
,
this
.
y
+
SnakeUtils
.
GRID_SIZE
);
case
EAST:
return
new
Location
(
this
.
x
+
SnakeUtils
.
GRID_SIZE
,
this
.
y
);
case
WEST:
return
new
Location
(
this
.
x
-
SnakeUtils
.
GRID_SIZE
,
this
.
y
);
case
NONE:
// fall through
default
:
return
this
;
}
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
{
return
true
;
}
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
{
return
false
;
}
Location
location
=
(
Location
)
o
;
if
(
this
.
x
!=
location
.
x
)
{
return
false
;
}
if
(
this
.
y
!=
location
.
y
)
{
return
false
;
}
return
true
;
}
@Override
public
int
hashCode
()
{
int
result
=
this
.
x
;
result
=
31
*
result
+
this
.
y
;
return
result
;
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/snake/Snake.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
snake
;
import
java.util.ArrayDeque
;
import
java.util.Collection
;
import
java.util.Deque
;
import
org.springframework.web.socket.TextMessage
;
import
org.springframework.web.socket.WebSocketSession
;
public
class
Snake
{
private
static
final
int
DEFAULT_LENGTH
=
5
;
private
final
Deque
<
Location
>
tail
=
new
ArrayDeque
<>();
private
final
Object
monitor
=
new
Object
();
private
final
int
id
;
private
final
WebSocketSession
session
;
private
final
String
hexColor
;
private
Direction
direction
;
private
int
length
=
DEFAULT_LENGTH
;
private
Location
head
;
public
Snake
(
int
id
,
WebSocketSession
session
)
{
this
.
id
=
id
;
this
.
session
=
session
;
this
.
hexColor
=
SnakeUtils
.
getRandomHexColor
();
resetState
();
}
private
void
resetState
()
{
this
.
direction
=
Direction
.
NONE
;
this
.
head
=
SnakeUtils
.
getRandomLocation
();
this
.
tail
.
clear
();
this
.
length
=
DEFAULT_LENGTH
;
}
private
void
kill
()
throws
Exception
{
synchronized
(
this
.
monitor
)
{
resetState
();
sendMessage
(
"{'type': 'dead'}"
);
}
}
private
void
reward
()
throws
Exception
{
synchronized
(
this
.
monitor
)
{
this
.
length
++;
sendMessage
(
"{'type': 'kill'}"
);
}
}
protected
void
sendMessage
(
String
msg
)
throws
Exception
{
this
.
session
.
sendMessage
(
new
TextMessage
(
msg
));
}
public
void
update
(
Collection
<
Snake
>
snakes
)
throws
Exception
{
synchronized
(
this
.
monitor
)
{
Location
nextLocation
=
this
.
head
.
getAdjacentLocation
(
this
.
direction
);
if
(
nextLocation
.
x
>=
SnakeUtils
.
PLAYFIELD_WIDTH
)
{
nextLocation
.
x
=
0
;
}
if
(
nextLocation
.
y
>=
SnakeUtils
.
PLAYFIELD_HEIGHT
)
{
nextLocation
.
y
=
0
;
}
if
(
nextLocation
.
x
<
0
)
{
nextLocation
.
x
=
SnakeUtils
.
PLAYFIELD_WIDTH
;
}
if
(
nextLocation
.
y
<
0
)
{
nextLocation
.
y
=
SnakeUtils
.
PLAYFIELD_HEIGHT
;
}
if
(
this
.
direction
!=
Direction
.
NONE
)
{
this
.
tail
.
addFirst
(
this
.
head
);
if
(
this
.
tail
.
size
()
>
this
.
length
)
{
this
.
tail
.
removeLast
();
}
this
.
head
=
nextLocation
;
}
handleCollisions
(
snakes
);
}
}
private
void
handleCollisions
(
Collection
<
Snake
>
snakes
)
throws
Exception
{
for
(
Snake
snake
:
snakes
)
{
boolean
headCollision
=
this
.
id
!=
snake
.
id
&&
snake
.
getHead
().
equals
(
this
.
head
);
boolean
tailCollision
=
snake
.
getTail
().
contains
(
this
.
head
);
if
(
headCollision
||
tailCollision
)
{
kill
();
if
(
this
.
id
!=
snake
.
id
)
{
snake
.
reward
();
}
}
}
}
public
Location
getHead
()
{
synchronized
(
this
.
monitor
)
{
return
this
.
head
;
}
}
public
Collection
<
Location
>
getTail
()
{
synchronized
(
this
.
monitor
)
{
return
this
.
tail
;
}
}
public
void
setDirection
(
Direction
direction
)
{
synchronized
(
this
.
monitor
)
{
this
.
direction
=
direction
;
}
}
public
String
getLocationsJson
()
{
synchronized
(
this
.
monitor
)
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
String
.
format
(
"{x: %d, y: %d}"
,
Integer
.
valueOf
(
this
.
head
.
x
),
Integer
.
valueOf
(
this
.
head
.
y
)));
for
(
Location
location
:
this
.
tail
)
{
sb
.
append
(
','
);
sb
.
append
(
String
.
format
(
"{x: %d, y: %d}"
,
Integer
.
valueOf
(
location
.
x
),
Integer
.
valueOf
(
location
.
y
)));
}
return
String
.
format
(
"{'id':%d,'body':[%s]}"
,
Integer
.
valueOf
(
this
.
id
),
sb
.
toString
());
}
}
public
int
getId
()
{
return
this
.
id
;
}
public
String
getHexColor
()
{
return
this
.
hexColor
;
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/snake/SnakeTimer.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
snake
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Iterator
;
import
java.util.Timer
;
import
java.util.TimerTask
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.CopyOnWriteArrayList
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
/**
* Sets up the timer for the multi-player snake game WebSocket example.
*/
public
final
class
SnakeTimer
{
private
static
final
long
TICK_DELAY
=
100
;
private
static
final
Object
MONITOR
=
new
Object
();
private
static
final
Log
logger
=
LogFactory
.
getLog
(
SnakeTimer
.
class
);
private
static
final
ConcurrentHashMap
<
Integer
,
Snake
>
snakes
=
new
ConcurrentHashMap
<>();
private
static
Timer
gameTimer
=
null
;
private
SnakeTimer
()
{
}
public
static
void
addSnake
(
Snake
snake
)
{
synchronized
(
MONITOR
)
{
if
(
snakes
.
isEmpty
())
{
startTimer
();
}
snakes
.
put
(
Integer
.
valueOf
(
snake
.
getId
()),
snake
);
}
}
public
static
Collection
<
Snake
>
getSnakes
()
{
return
Collections
.
unmodifiableCollection
(
snakes
.
values
());
}
public
static
void
removeSnake
(
Snake
snake
)
{
synchronized
(
MONITOR
)
{
snakes
.
remove
(
Integer
.
valueOf
(
snake
.
getId
()));
if
(
snakes
.
isEmpty
())
{
stopTimer
();
}
}
}
public
static
void
tick
()
throws
Exception
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
Iterator
<
Snake
>
iterator
=
SnakeTimer
.
getSnakes
().
iterator
();
iterator
.
hasNext
();)
{
Snake
snake
=
iterator
.
next
();
snake
.
update
(
SnakeTimer
.
getSnakes
());
sb
.
append
(
snake
.
getLocationsJson
());
if
(
iterator
.
hasNext
())
{
sb
.
append
(
','
);
}
}
broadcast
(
String
.
format
(
"{'type': 'update', 'data' : [%s]}"
,
sb
.
toString
()));
}
public
static
void
broadcast
(
String
message
)
throws
Exception
{
Collection
<
Snake
>
snakes
=
new
CopyOnWriteArrayList
<>(
SnakeTimer
.
getSnakes
());
for
(
Snake
snake
:
snakes
)
{
try
{
snake
.
sendMessage
(
message
);
}
catch
(
Throwable
ex
)
{
// if Snake#sendMessage fails the client is removed
removeSnake
(
snake
);
}
}
}
public
static
void
startTimer
()
{
gameTimer
=
new
Timer
(
SnakeTimer
.
class
.
getSimpleName
()
+
" Timer"
);
gameTimer
.
scheduleAtFixedRate
(
new
TimerTask
()
{
@Override
public
void
run
()
{
try
{
tick
();
}
catch
(
Throwable
ex
)
{
logger
.
error
(
"Caught to prevent timer from shutting down"
,
ex
);
}
}
},
TICK_DELAY
,
TICK_DELAY
);
}
public
static
void
stopTimer
()
{
if
(
gameTimer
!=
null
)
{
gameTimer
.
cancel
();
}
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/snake/SnakeUtils.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
snake
;
import
java.awt.Color
;
import
java.util.Random
;
public
final
class
SnakeUtils
{
/**
* The width of the playfield.
*/
public
static
final
int
PLAYFIELD_WIDTH
=
640
;
/**
* The height of the playfield.
*/
public
static
final
int
PLAYFIELD_HEIGHT
=
480
;
/**
* The grid size.
*/
public
static
final
int
GRID_SIZE
=
10
;
private
static
final
Random
random
=
new
Random
();
private
SnakeUtils
()
{
}
public
static
String
getRandomHexColor
()
{
float
hue
=
random
.
nextFloat
();
// sat between 0.1 and 0.3
float
saturation
=
(
random
.
nextInt
(
2000
)
+
1000
)
/
10000
f
;
float
luminance
=
0.9f
;
Color
color
=
Color
.
getHSBColor
(
hue
,
saturation
,
luminance
);
return
'#'
+
Integer
.
toHexString
((
color
.
getRGB
()
&
0xffffff
)
|
0x1000000
).
substring
(
1
);
}
public
static
Location
getRandomLocation
()
{
int
x
=
roundByGridSize
(
random
.
nextInt
(
PLAYFIELD_WIDTH
));
int
y
=
roundByGridSize
(
random
.
nextInt
(
PLAYFIELD_HEIGHT
));
return
new
Location
(
x
,
y
);
}
private
static
int
roundByGridSize
(
int
value
)
{
value
=
value
+
(
GRID_SIZE
/
2
);
value
=
value
/
GRID_SIZE
;
value
=
value
*
GRID_SIZE
;
return
value
;
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/java/smoketest/websocket/jetty/snake/SnakeWebSocketHandler.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
snake
;
import
java.awt.Color
;
import
java.util.Iterator
;
import
java.util.Random
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
org.springframework.web.socket.CloseStatus
;
import
org.springframework.web.socket.TextMessage
;
import
org.springframework.web.socket.WebSocketSession
;
import
org.springframework.web.socket.handler.TextWebSocketHandler
;
public
class
SnakeWebSocketHandler
extends
TextWebSocketHandler
{
private
static
final
AtomicInteger
snakeIds
=
new
AtomicInteger
();
private
static
final
Random
random
=
new
Random
();
private
final
int
id
;
private
Snake
snake
;
public
static
String
getRandomHexColor
()
{
float
hue
=
random
.
nextFloat
();
// sat between 0.1 and 0.3
float
saturation
=
(
random
.
nextInt
(
2000
)
+
1000
)
/
10000
f
;
float
luminance
=
0.9f
;
Color
color
=
Color
.
getHSBColor
(
hue
,
saturation
,
luminance
);
return
'#'
+
Integer
.
toHexString
((
color
.
getRGB
()
&
0xffffff
)
|
0x1000000
).
substring
(
1
);
}
public
static
Location
getRandomLocation
()
{
int
x
=
roundByGridSize
(
random
.
nextInt
(
SnakeUtils
.
PLAYFIELD_WIDTH
));
int
y
=
roundByGridSize
(
random
.
nextInt
(
SnakeUtils
.
PLAYFIELD_HEIGHT
));
return
new
Location
(
x
,
y
);
}
private
static
int
roundByGridSize
(
int
value
)
{
value
=
value
+
(
SnakeUtils
.
GRID_SIZE
/
2
);
value
=
value
/
SnakeUtils
.
GRID_SIZE
;
value
=
value
*
SnakeUtils
.
GRID_SIZE
;
return
value
;
}
public
SnakeWebSocketHandler
()
{
this
.
id
=
snakeIds
.
getAndIncrement
();
}
@Override
public
void
afterConnectionEstablished
(
WebSocketSession
session
)
throws
Exception
{
this
.
snake
=
new
Snake
(
this
.
id
,
session
);
SnakeTimer
.
addSnake
(
this
.
snake
);
StringBuilder
sb
=
new
StringBuilder
();
for
(
Iterator
<
Snake
>
iterator
=
SnakeTimer
.
getSnakes
().
iterator
();
iterator
.
hasNext
();)
{
Snake
snake
=
iterator
.
next
();
sb
.
append
(
String
.
format
(
"{id: %d, color: '%s'}"
,
Integer
.
valueOf
(
snake
.
getId
()),
snake
.
getHexColor
()));
if
(
iterator
.
hasNext
())
{
sb
.
append
(
','
);
}
}
SnakeTimer
.
broadcast
(
String
.
format
(
"{'type': 'join','data':[%s]}"
,
sb
.
toString
()));
}
@Override
protected
void
handleTextMessage
(
WebSocketSession
session
,
TextMessage
message
)
throws
Exception
{
String
payload
=
message
.
getPayload
();
if
(
"west"
.
equals
(
payload
))
{
this
.
snake
.
setDirection
(
Direction
.
WEST
);
}
else
if
(
"north"
.
equals
(
payload
))
{
this
.
snake
.
setDirection
(
Direction
.
NORTH
);
}
else
if
(
"east"
.
equals
(
payload
))
{
this
.
snake
.
setDirection
(
Direction
.
EAST
);
}
else
if
(
"south"
.
equals
(
payload
))
{
this
.
snake
.
setDirection
(
Direction
.
SOUTH
);
}
}
@Override
public
void
afterConnectionClosed
(
WebSocketSession
session
,
CloseStatus
status
)
throws
Exception
{
SnakeTimer
.
removeSnake
(
this
.
snake
);
SnakeTimer
.
broadcast
(
String
.
format
(
"{'type': 'leave', 'id': %d}"
,
Integer
.
valueOf
(
this
.
id
)));
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/resources/static/echo.html
0 → 100644
View file @
bc7004d9
<!--
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
https://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.
-->
<!DOCTYPE html>
<html>
<head>
<title>
Apache Tomcat WebSocket Examples: Echo
</title>
<style
type=
"text/css"
>
#connect-container
{
float
:
left
;
width
:
400px
}
#connect-container
div
{
padding
:
5px
;
}
#console-container
{
float
:
left
;
margin-left
:
15px
;
width
:
400px
;
}
#console
{
border
:
1px
solid
#CCCCCC
;
border-right-color
:
#999999
;
border-bottom-color
:
#999999
;
height
:
170px
;
overflow-y
:
scroll
;
padding
:
5px
;
width
:
100%
;
}
#console
p
{
padding
:
0
;
margin
:
0
;
}
</style>
<script
src=
"https://cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"
></script>
<script
type=
"text/javascript"
>
var
ws
=
null
;
function
setConnected
(
connected
)
{
document
.
getElementById
(
'connect'
).
disabled
=
connected
;
document
.
getElementById
(
'disconnect'
).
disabled
=
!
connected
;
document
.
getElementById
(
'echo'
).
disabled
=
!
connected
;
}
function
connect
()
{
var
target
=
document
.
getElementById
(
'target'
).
value
;
ws
=
new
SockJS
(
target
);
ws
.
onopen
=
function
()
{
setConnected
(
true
);
log
(
'Info: WebSocket connection opened.'
);
};
ws
.
onmessage
=
function
(
event
)
{
log
(
'Received: '
+
event
.
data
);
};
ws
.
onclose
=
function
()
{
setConnected
(
false
);
log
(
'Info: WebSocket connection closed.'
);
};
}
function
disconnect
()
{
if
(
ws
!=
null
)
{
ws
.
close
();
ws
=
null
;
}
setConnected
(
false
);
}
function
echo
()
{
if
(
ws
!=
null
)
{
var
message
=
document
.
getElementById
(
'message'
).
value
;
log
(
'Sent: '
+
message
);
ws
.
send
(
message
);
}
else
{
alert
(
'WebSocket connection not established, please connect.'
);
}
}
function
log
(
message
)
{
var
console
=
document
.
getElementById
(
'console'
);
var
p
=
document
.
createElement
(
'p'
);
p
.
style
.
wordWrap
=
'break-word'
;
p
.
appendChild
(
document
.
createTextNode
(
message
));
console
.
appendChild
(
p
);
while
(
console
.
childNodes
.
length
>
25
)
{
console
.
removeChild
(
console
.
firstChild
);
}
console
.
scrollTop
=
console
.
scrollHeight
;
}
</script>
</head>
<body>
<noscript><h2
style=
"color: #ff0000"
>
Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable
Javascript and reload this page!
</h2></noscript>
<div>
<div
id=
"connect-container"
>
<div>
<input
id=
"target"
type=
"text"
size=
"40"
style=
"width: 350px"
value=
"/echo"
/>
</div>
<div>
<button
id=
"connect"
onclick=
"connect();"
>
Connect
</button>
<button
id=
"disconnect"
disabled=
"disabled"
onclick=
"disconnect();"
>
Disconnect
</button>
</div>
<div>
<textarea
id=
"message"
style=
"width: 350px"
>
Here is a message!
</textarea>
</div>
<div>
<button
id=
"echo"
onclick=
"echo();"
disabled=
"disabled"
>
Echo message
</button>
</div>
</div>
<div
id=
"console-container"
>
<div
id=
"console"
></div>
</div>
</div>
</body>
</html>
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/resources/static/index.html
0 → 100644
View file @
bc7004d9
<!--
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
https://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.
-->
<!DOCTYPE html>
<html>
<head>
<title>
Apache Tomcat WebSocket Examples: Index
</title>
</head>
<body>
<noscript><h2
style=
"color: #ff0000"
>
Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable
Javascript and reload this page!
</h2></noscript>
<p>
Please select the sample you would like to try.
</p>
<ul>
<li><a
href=
"./echo.html"
>
Echo
</a></li>
<li><a
href=
"./reverse.html"
>
Reverse
</a></li>
<li><a
href=
"./snake.html"
>
Snake
</a></li>
</ul>
</body>
</html>
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/resources/static/reverse.html
0 → 100644
View file @
bc7004d9
<!--
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
https://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.
-->
<!DOCTYPE html>
<html>
<head>
<title>
WebSocket Examples: Reverse
</title>
<style
type=
"text/css"
>
#connect-container
{
float
:
left
;
width
:
400px
}
#connect-container
div
{
padding
:
5px
;
}
#console-container
{
float
:
left
;
margin-left
:
15px
;
width
:
400px
;
}
#console
{
border
:
1px
solid
#CCCCCC
;
border-right-color
:
#999999
;
border-bottom-color
:
#999999
;
height
:
170px
;
overflow-y
:
scroll
;
padding
:
5px
;
width
:
100%
;
}
#console
p
{
padding
:
0
;
margin
:
0
;
}
</style>
<script
type=
"text/javascript"
>
var
ws
=
null
;
function
setConnected
(
connected
)
{
document
.
getElementById
(
'connect'
).
disabled
=
connected
;
document
.
getElementById
(
'disconnect'
).
disabled
=
!
connected
;
document
.
getElementById
(
'reverse'
).
disabled
=
!
connected
;
}
function
connect
()
{
var
target
=
document
.
getElementById
(
'target'
).
value
;
ws
=
new
WebSocket
(
target
);
ws
.
onopen
=
function
()
{
setConnected
(
true
);
log
(
'Info: WebSocket connection opened.'
);
};
ws
.
onmessage
=
function
(
event
)
{
log
(
'Received: '
+
event
.
data
);
};
ws
.
onclose
=
function
()
{
setConnected
(
false
);
log
(
'Info: WebSocket connection closed.'
);
};
}
function
updateTarget
()
{
if
(
window
.
location
.
protocol
==
'http:'
)
{
document
.
getElementById
(
'target'
).
value
=
'ws://'
+
window
.
location
.
host
+
document
.
getElementById
(
'target'
).
value
;
}
else
{
document
.
getElementById
(
'target'
).
value
=
'wss://'
+
window
.
location
.
host
+
document
.
getElementById
(
'target'
).
value
;
}
}
function
disconnect
()
{
if
(
ws
!=
null
)
{
ws
.
close
();
ws
=
null
;
}
setConnected
(
false
);
}
function
reverse
()
{
if
(
ws
!=
null
)
{
var
message
=
document
.
getElementById
(
'message'
).
value
;
log
(
'Sent: '
+
message
);
ws
.
send
(
message
);
}
else
{
alert
(
'WebSocket connection not established, please connect.'
);
}
}
function
log
(
message
)
{
var
console
=
document
.
getElementById
(
'console'
);
var
p
=
document
.
createElement
(
'p'
);
p
.
style
.
wordWrap
=
'break-word'
;
p
.
appendChild
(
document
.
createTextNode
(
message
));
console
.
appendChild
(
p
);
while
(
console
.
childNodes
.
length
>
25
)
{
console
.
removeChild
(
console
.
firstChild
);
}
console
.
scrollTop
=
console
.
scrollHeight
;
}
</script>
</head>
<body
onload=
"updateTarget()"
>
<noscript><h2
style=
"color: #ff0000"
>
Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable
Javascript and reload this page!
</h2></noscript>
<div>
<div
id=
"connect-container"
>
<div>
<input
id=
"target"
type=
"text"
size=
"40"
style=
"width: 350px"
value=
"/reverse"
/>
</div>
<div>
<button
id=
"connect"
onclick=
"connect();"
>
Connect
</button>
<button
id=
"disconnect"
disabled=
"disabled"
onclick=
"disconnect();"
>
Disconnect
</button>
</div>
<div>
<textarea
id=
"message"
style=
"width: 350px"
>
Here is a message!
</textarea>
</div>
<div>
<button
id=
"reverse"
onclick=
"reverse();"
disabled=
"disabled"
>
Reverse message
</button>
</div>
</div>
<div
id=
"console-container"
>
<div
id=
"console"
></div>
</div>
</div>
</body>
</html>
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/main/resources/static/snake.html
0 → 100644
View file @
bc7004d9
<!--
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
https://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.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns=
"http://www.w3.org/1999/xhtml"
lang=
"en"
xml:lang=
"en"
>
<head>
<meta
http-equiv=
"Content-Type"
content=
"text/html; charset=utf-8"
/>
<title>
Apache Tomcat WebSocket Examples: Multiplayer Snake
</title>
<style
type=
"text/css"
>
#playground
{
width
:
640px
;
height
:
480px
;
background-color
:
#000
;
}
#console-container
{
float
:
left
;
margin-left
:
15px
;
width
:
300px
;
}
#console
{
border
:
1px
solid
#CCCCCC
;
border-right-color
:
#999999
;
border-bottom-color
:
#999999
;
height
:
480px
;
overflow-y
:
scroll
;
padding-left
:
5px
;
padding-right
:
5px
;
width
:
100%
;
}
#console
p
{
padding
:
0
;
margin
:
0
;
}
</style>
<script
src=
"https://cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js"
></script>
</head>
<body>
<noscript><h2
style=
"color: #ff0000"
>
Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable
Javascript and reload this page!
</h2></noscript>
<div
style=
"float: left"
>
<canvas
id=
"playground"
width=
"640"
height=
"480"
></canvas>
</div>
<div
id=
"console-container"
>
<div
id=
"console"
></div>
</div>
<script
type=
"text/javascript"
>
var
Game
=
{};
Game
.
fps
=
30
;
Game
.
socket
=
null
;
Game
.
nextFrame
=
null
;
Game
.
interval
=
null
;
Game
.
direction
=
'none'
;
Game
.
gridSize
=
10
;
function
Snake
()
{
this
.
snakeBody
=
[];
this
.
color
=
null
;
}
Snake
.
prototype
.
draw
=
function
(
context
)
{
for
(
var
id
in
this
.
snakeBody
)
{
context
.
fillStyle
=
this
.
color
;
context
.
fillRect
(
this
.
snakeBody
[
id
].
x
,
this
.
snakeBody
[
id
].
y
,
Game
.
gridSize
,
Game
.
gridSize
);
}
};
Game
.
initialize
=
function
()
{
this
.
entities
=
[];
canvas
=
document
.
getElementById
(
'playground'
);
if
(
!
canvas
.
getContext
)
{
Console
.
log
(
'Error: 2d canvas not supported by this browser.'
);
return
;
}
this
.
context
=
canvas
.
getContext
(
'2d'
);
window
.
addEventListener
(
'keydown'
,
function
(
e
)
{
var
code
=
e
.
keyCode
;
if
(
code
>
36
&&
code
<
41
)
{
switch
(
code
)
{
case
37
:
if
(
Game
.
direction
!=
'east'
)
Game
.
setDirection
(
'west'
);
break
;
case
38
:
if
(
Game
.
direction
!=
'south'
)
Game
.
setDirection
(
'north'
);
break
;
case
39
:
if
(
Game
.
direction
!=
'west'
)
Game
.
setDirection
(
'east'
);
break
;
case
40
:
if
(
Game
.
direction
!=
'north'
)
Game
.
setDirection
(
'south'
);
break
;
}
}
},
false
);
Game
.
connect
();
};
Game
.
setDirection
=
function
(
direction
)
{
Game
.
direction
=
direction
;
Game
.
socket
.
send
(
direction
);
Console
.
log
(
'Sent: Direction '
+
direction
);
};
Game
.
startGameLoop
=
function
()
{
if
(
window
.
webkitRequestAnimationFrame
)
{
Game
.
nextFrame
=
function
()
{
webkitRequestAnimationFrame
(
Game
.
run
);
};
}
else
if
(
window
.
mozRequestAnimationFrame
)
{
Game
.
nextFrame
=
function
()
{
mozRequestAnimationFrame
(
Game
.
run
);
};
}
else
{
Game
.
interval
=
setInterval
(
Game
.
run
,
1000
/
Game
.
fps
);
}
if
(
Game
.
nextFrame
!=
null
)
{
Game
.
nextFrame
();
}
};
Game
.
stopGameLoop
=
function
()
{
Game
.
nextFrame
=
null
;
if
(
Game
.
interval
!=
null
)
{
clearInterval
(
Game
.
interval
);
}
};
Game
.
draw
=
function
()
{
this
.
context
.
clearRect
(
0
,
0
,
640
,
480
);
for
(
var
id
in
this
.
entities
)
{
this
.
entities
[
id
].
draw
(
this
.
context
);
}
};
Game
.
addSnake
=
function
(
id
,
color
)
{
Game
.
entities
[
id
]
=
new
Snake
();
Game
.
entities
[
id
].
color
=
color
;
};
Game
.
updateSnake
=
function
(
id
,
snakeBody
)
{
if
(
typeof
Game
.
entities
[
id
]
!=
"undefined"
)
{
Game
.
entities
[
id
].
snakeBody
=
snakeBody
;
}
};
Game
.
removeSnake
=
function
(
id
)
{
Game
.
entities
[
id
]
=
null
;
// Force GC.
delete
Game
.
entities
[
id
];
};
Game
.
run
=
(
function
()
{
var
skipTicks
=
1000
/
Game
.
fps
,
nextGameTick
=
(
new
Date
).
getTime
();
return
function
()
{
while
((
new
Date
).
getTime
()
>
nextGameTick
)
{
nextGameTick
+=
skipTicks
;
}
Game
.
draw
();
if
(
Game
.
nextFrame
!=
null
)
{
Game
.
nextFrame
();
}
};
})();
Game
.
connect
=
(
function
()
{
Game
.
socket
=
new
SockJS
(
"/snake"
);
Game
.
socket
.
onopen
=
function
()
{
// Socket open.. start the game loop.
Console
.
log
(
'Info: WebSocket connection opened.'
);
Console
.
log
(
'Info: Press an arrow key to begin.'
);
Game
.
startGameLoop
();
setInterval
(
function
()
{
// Prevent server read timeout.
Game
.
socket
.
send
(
'ping'
);
},
5000
);
};
Game
.
socket
.
onclose
=
function
()
{
Console
.
log
(
'Info: WebSocket closed.'
);
Game
.
stopGameLoop
();
};
Game
.
socket
.
onmessage
=
function
(
message
)
{
// _Potential_ security hole, consider using json lib to parse data in production.
var
packet
=
eval
(
'('
+
message
.
data
+
')'
);
switch
(
packet
.
type
)
{
case
'update'
:
for
(
var
i
=
0
;
i
<
packet
.
data
.
length
;
i
++
)
{
Game
.
updateSnake
(
packet
.
data
[
i
].
id
,
packet
.
data
[
i
].
body
);
}
break
;
case
'join'
:
for
(
var
j
=
0
;
j
<
packet
.
data
.
length
;
j
++
)
{
Game
.
addSnake
(
packet
.
data
[
j
].
id
,
packet
.
data
[
j
].
color
);
}
break
;
case
'leave'
:
Game
.
removeSnake
(
packet
.
id
);
break
;
case
'dead'
:
Console
.
log
(
'Info: Your snake is dead, bad luck!'
);
Game
.
direction
=
'none'
;
break
;
case
'kill'
:
Console
.
log
(
'Info: Head shot!'
);
break
;
}
};
});
var
Console
=
{};
Console
.
log
=
(
function
(
message
)
{
var
console
=
document
.
getElementById
(
'console'
);
var
p
=
document
.
createElement
(
'p'
);
p
.
style
.
wordWrap
=
'break-word'
;
p
.
innerHTML
=
message
;
console
.
appendChild
(
p
);
while
(
console
.
childNodes
.
length
>
25
)
{
console
.
removeChild
(
console
.
firstChild
);
}
console
.
scrollTop
=
console
.
scrollHeight
;
});
Game
.
initialize
();
</script>
</body>
</html>
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/test/java/smoketest/websocket/jetty/SampleJetty10WebSocketsApplicationTests.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicReference
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.junit.jupiter.api.Test
;
import
org.junit.jupiter.api.condition.EnabledForJreRange
;
import
org.junit.jupiter.api.condition.JRE
;
import
smoketest.websocket.jetty10.client.GreetingService
;
import
smoketest.websocket.jetty10.client.SimpleClientWebSocketHandler
;
import
smoketest.websocket.jetty10.client.SimpleGreetingService
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.CommandLineRunner
;
import
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.boot.test.context.SpringBootTest.WebEnvironment
;
import
org.springframework.boot.web.server.LocalServerPort
;
import
org.springframework.context.ConfigurableApplicationContext
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.socket.client.WebSocketConnectionManager
;
import
org.springframework.web.socket.client.standard.StandardWebSocketClient
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
@EnabledForJreRange
(
min
=
JRE
.
JAVA_11
)
@SpringBootTest
(
classes
=
SampleJetty10WebSocketsApplication
.
class
,
webEnvironment
=
WebEnvironment
.
RANDOM_PORT
,
properties
=
"debug: true"
)
class
SampleJetty10WebSocketsApplicationTests
{
private
static
Log
logger
=
LogFactory
.
getLog
(
SampleJetty10WebSocketsApplicationTests
.
class
);
@LocalServerPort
private
int
port
=
1234
;
@Test
void
echoEndpoint
()
{
ConfigurableApplicationContext
context
=
new
SpringApplicationBuilder
(
ClientConfiguration
.
class
,
PropertyPlaceholderAutoConfiguration
.
class
)
.
properties
(
"websocket.uri:ws://localhost:"
+
this
.
port
+
"/echo/websocket"
)
.
run
(
"--spring.main.web-application-type=none"
);
long
count
=
context
.
getBean
(
ClientConfiguration
.
class
).
latch
.
getCount
();
AtomicReference
<
String
>
messagePayloadReference
=
context
.
getBean
(
ClientConfiguration
.
class
).
messagePayload
;
context
.
close
();
assertThat
(
count
).
isEqualTo
(
0
);
assertThat
(
messagePayloadReference
.
get
()).
isEqualTo
(
"Did you say \"Hello world!\"?"
);
}
@Test
void
reverseEndpoint
()
{
ConfigurableApplicationContext
context
=
new
SpringApplicationBuilder
(
ClientConfiguration
.
class
,
PropertyPlaceholderAutoConfiguration
.
class
)
.
properties
(
"websocket.uri:ws://localhost:"
+
this
.
port
+
"/reverse"
)
.
run
(
"--spring.main.web-application-type=none"
);
long
count
=
context
.
getBean
(
ClientConfiguration
.
class
).
latch
.
getCount
();
AtomicReference
<
String
>
messagePayloadReference
=
context
.
getBean
(
ClientConfiguration
.
class
).
messagePayload
;
context
.
close
();
assertThat
(
count
).
isEqualTo
(
0
);
assertThat
(
messagePayloadReference
.
get
()).
isEqualTo
(
"Reversed: !dlrow olleH"
);
}
@Configuration
(
proxyBeanMethods
=
false
)
static
class
ClientConfiguration
implements
CommandLineRunner
{
@Value
(
"${websocket.uri}"
)
private
String
webSocketUri
;
private
final
CountDownLatch
latch
=
new
CountDownLatch
(
1
);
private
final
AtomicReference
<
String
>
messagePayload
=
new
AtomicReference
<>();
@Override
public
void
run
(
String
...
args
)
throws
Exception
{
logger
.
info
(
"Waiting for response: latch="
+
this
.
latch
.
getCount
());
if
(
this
.
latch
.
await
(
10
,
TimeUnit
.
SECONDS
))
{
logger
.
info
(
"Got response: "
+
this
.
messagePayload
.
get
());
}
else
{
logger
.
info
(
"Response not received: latch="
+
this
.
latch
.
getCount
());
}
}
@Bean
WebSocketConnectionManager
wsConnectionManager
()
{
WebSocketConnectionManager
manager
=
new
WebSocketConnectionManager
(
client
(),
handler
(),
this
.
webSocketUri
);
manager
.
setAutoStartup
(
true
);
return
manager
;
}
@Bean
StandardWebSocketClient
client
()
{
return
new
StandardWebSocketClient
();
}
@Bean
SimpleClientWebSocketHandler
handler
()
{
return
new
SimpleClientWebSocketHandler
(
greetingService
(),
this
.
latch
,
this
.
messagePayload
);
}
@Bean
GreetingService
greetingService
()
{
return
new
SimpleGreetingService
();
}
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/test/java/smoketest/websocket/jetty/echo/CustomContainerWebSocketsApplicationTests.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
echo
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicReference
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.junit.jupiter.api.Test
;
import
org.junit.jupiter.api.condition.EnabledForJreRange
;
import
org.junit.jupiter.api.condition.JRE
;
import
smoketest.websocket.jetty10.SampleJetty10WebSocketsApplication
;
import
smoketest.websocket.jetty10.client.GreetingService
;
import
smoketest.websocket.jetty10.client.SimpleClientWebSocketHandler
;
import
smoketest.websocket.jetty10.client.SimpleGreetingService
;
import
smoketest.websocket.jetty10.echo.CustomContainerWebSocketsApplicationTests.CustomContainerConfiguration
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.CommandLineRunner
;
import
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.boot.test.context.SpringBootTest.WebEnvironment
;
import
org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory
;
import
org.springframework.boot.web.server.LocalServerPort
;
import
org.springframework.boot.web.servlet.server.ServletWebServerFactory
;
import
org.springframework.context.ConfigurableApplicationContext
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.socket.client.WebSocketConnectionManager
;
import
org.springframework.web.socket.client.standard.StandardWebSocketClient
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
@EnabledForJreRange
(
min
=
JRE
.
JAVA_11
)
@SpringBootTest
(
classes
=
{
SampleJetty10WebSocketsApplication
.
class
,
CustomContainerConfiguration
.
class
},
webEnvironment
=
WebEnvironment
.
RANDOM_PORT
)
class
CustomContainerWebSocketsApplicationTests
{
private
static
Log
logger
=
LogFactory
.
getLog
(
CustomContainerWebSocketsApplicationTests
.
class
);
@LocalServerPort
private
int
port
;
@Test
void
echoEndpoint
()
{
ConfigurableApplicationContext
context
=
new
SpringApplicationBuilder
(
ClientConfiguration
.
class
,
PropertyPlaceholderAutoConfiguration
.
class
)
.
properties
(
"websocket.uri:ws://localhost:"
+
this
.
port
+
"/ws/echo/websocket"
)
.
run
(
"--spring.main.web-application-type=none"
);
long
count
=
context
.
getBean
(
ClientConfiguration
.
class
).
latch
.
getCount
();
AtomicReference
<
String
>
messagePayloadReference
=
context
.
getBean
(
ClientConfiguration
.
class
).
messagePayload
;
context
.
close
();
assertThat
(
count
).
isEqualTo
(
0
);
assertThat
(
messagePayloadReference
.
get
()).
isEqualTo
(
"Did you say \"Hello world!\"?"
);
}
@Test
void
reverseEndpoint
()
{
ConfigurableApplicationContext
context
=
new
SpringApplicationBuilder
(
ClientConfiguration
.
class
,
PropertyPlaceholderAutoConfiguration
.
class
)
.
properties
(
"websocket.uri:ws://localhost:"
+
this
.
port
+
"/ws/reverse"
)
.
run
(
"--spring.main.web-application-type=none"
);
long
count
=
context
.
getBean
(
ClientConfiguration
.
class
).
latch
.
getCount
();
AtomicReference
<
String
>
messagePayloadReference
=
context
.
getBean
(
ClientConfiguration
.
class
).
messagePayload
;
context
.
close
();
assertThat
(
count
).
isEqualTo
(
0
);
assertThat
(
messagePayloadReference
.
get
()).
isEqualTo
(
"Reversed: !dlrow olleH"
);
}
@Configuration
(
proxyBeanMethods
=
false
)
protected
static
class
CustomContainerConfiguration
{
@Bean
public
ServletWebServerFactory
webServerFactory
()
{
return
new
JettyServletWebServerFactory
(
"/ws"
,
0
);
}
}
@Configuration
(
proxyBeanMethods
=
false
)
static
class
ClientConfiguration
implements
CommandLineRunner
{
@Value
(
"${websocket.uri}"
)
private
String
webSocketUri
;
private
final
CountDownLatch
latch
=
new
CountDownLatch
(
1
);
private
final
AtomicReference
<
String
>
messagePayload
=
new
AtomicReference
<>();
@Override
public
void
run
(
String
...
args
)
throws
Exception
{
logger
.
info
(
"Waiting for response: latch="
+
this
.
latch
.
getCount
());
if
(
this
.
latch
.
await
(
10
,
TimeUnit
.
SECONDS
))
{
logger
.
info
(
"Got response: "
+
this
.
messagePayload
.
get
());
}
else
{
logger
.
info
(
"Response not received: latch="
+
this
.
latch
.
getCount
());
}
}
@Bean
WebSocketConnectionManager
wsConnectionManager
()
{
WebSocketConnectionManager
manager
=
new
WebSocketConnectionManager
(
client
(),
handler
(),
this
.
webSocketUri
);
manager
.
setAutoStartup
(
true
);
return
manager
;
}
@Bean
StandardWebSocketClient
client
()
{
return
new
StandardWebSocketClient
();
}
@Bean
SimpleClientWebSocketHandler
handler
()
{
return
new
SimpleClientWebSocketHandler
(
greetingService
(),
this
.
latch
,
this
.
messagePayload
);
}
@Bean
GreetingService
greetingService
()
{
return
new
SimpleGreetingService
();
}
}
}
spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-websocket-jetty10/src/test/java/smoketest/websocket/jetty/snake/SnakeTimerTests.java
0 → 100644
View file @
bc7004d9
/*
* Copyright 2012-2021 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
*
* https://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
smoketest
.
websocket
.
jetty10
.
snake
;
import
java.io.IOException
;
import
org.junit.jupiter.api.Test
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
anyString
;
import
static
org
.
mockito
.
BDDMockito
.
willThrow
;
import
static
org
.
mockito
.
Mockito
.
mock
;
class
SnakeTimerTests
{
@Test
void
removeDysfunctionalSnakes
()
throws
Exception
{
Snake
snake
=
mock
(
Snake
.
class
);
willThrow
(
new
IOException
()).
given
(
snake
).
sendMessage
(
anyString
());
SnakeTimer
.
addSnake
(
snake
);
SnakeTimer
.
broadcast
(
""
);
assertThat
(
SnakeTimer
.
getSnakes
()).
hasSize
(
0
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment