Skip to content

Commit bd9cfd1

Browse files
author
Abhishek
committed
commit #1
0 parents  commit bd9cfd1

File tree

10 files changed

+640
-0
lines changed

10 files changed

+640
-0
lines changed

Diff for: README.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Bunch of tests for scenario where WebSocket endpoints are decorated with EJBs. This is might be helpful when reading through the [EJB integration section of the Java WebSocket API Handbook
2+
](https://abhirockzz.gitbooks.io/java-websocket-api-handbook/content/part-1-tying_in_with_the_java_ee_platform.html#decorating-websocket-endpoints-with-ejb). This helps validate the behavior which might be a source of confusion since there are two specifications at play here. This is not something which is supported by the WebSocket specification but it is supported by Tyrus (hence you can try this on GlassFish or Payara)
3+
4+
## Scenarios
5+
6+
- A new stateless EJB (from the pool) is allocated for a WebSocket client
7+
- A stateless EJB (once allocated) remains attached to a WebSocket client throughout it's lifecycle
8+
- The same Singleton bean instance is used for WebSocket clients (`Session`s)
9+
- A unique Stateful session bean instance is allocated to each unique client
10+
11+
## Build & run
12+
13+
There are two Maven projects
14+
15+
- First one is a simple Java EE (WAR) application with EJB-WebSocket endpoints
16+
- The second one contains the tests
17+
18+
Download the project to your machine. To try things out, first build and deploy the application on on GlassFish or Payara
19+
20+
- cd application
21+
- `mvn clean install`
22+
- deploy....
23+
24+
Then, run the tests
25+
26+
- cd tests
27+
- `mvn test`
28+
29+
Note: if required, change the host port here before running the tests

Diff for: application/pom.xml

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<groupId>com.wordpress.abhirockzz</groupId>
6+
<artifactId>websocket-ejb</artifactId>
7+
<version>1.0</version>
8+
<packaging>war</packaging>
9+
10+
<name>websocket-ejb</name>
11+
12+
<properties>
13+
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
</properties>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>javax</groupId>
20+
<artifactId>javaee-web-api</artifactId>
21+
<version>7.0</version>
22+
<scope>provided</scope>
23+
</dependency>
24+
</dependencies>
25+
26+
<build>
27+
<finalName>websocket-ejb</finalName>
28+
<plugins>
29+
<plugin>
30+
<groupId>org.apache.maven.plugins</groupId>
31+
<artifactId>maven-compiler-plugin</artifactId>
32+
<version>3.1</version>
33+
<configuration>
34+
<source>1.7</source>
35+
<target>1.7</target>
36+
<compilerArguments>
37+
<endorseddirs>${endorsed.dir}</endorseddirs>
38+
</compilerArguments>
39+
</configuration>
40+
</plugin>
41+
<plugin>
42+
<groupId>org.apache.maven.plugins</groupId>
43+
<artifactId>maven-war-plugin</artifactId>
44+
<version>2.3</version>
45+
<configuration>
46+
<failOnMissingWebXml>false</failOnMissingWebXml>
47+
</configuration>
48+
</plugin>
49+
<plugin>
50+
<groupId>org.apache.maven.plugins</groupId>
51+
<artifactId>maven-dependency-plugin</artifactId>
52+
<version>2.6</version>
53+
<executions>
54+
<execution>
55+
<phase>validate</phase>
56+
<goals>
57+
<goal>copy</goal>
58+
</goals>
59+
<configuration>
60+
<outputDirectory>${endorsed.dir}</outputDirectory>
61+
<silent>true</silent>
62+
<artifactItems>
63+
<artifactItem>
64+
<groupId>javax</groupId>
65+
<artifactId>javaee-endorsed-api</artifactId>
66+
<version>7.0</version>
67+
<type>jar</type>
68+
</artifactItem>
69+
</artifactItems>
70+
</configuration>
71+
</execution>
72+
</executions>
73+
</plugin>
74+
</plugins>
75+
</build>
76+
77+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.gitbooks.abhirockzz.jwah.websocketejb;
2+
3+
import java.io.IOException;
4+
import javax.annotation.PreDestroy;
5+
import javax.ejb.Lock;
6+
import javax.ejb.LockType;
7+
8+
import javax.ejb.Singleton;
9+
10+
import javax.websocket.CloseReason;
11+
import javax.websocket.OnClose;
12+
import javax.websocket.OnMessage;
13+
import javax.websocket.OnOpen;
14+
import javax.websocket.Session;
15+
import javax.websocket.server.ServerEndpoint;
16+
17+
@Singleton
18+
@ServerEndpoint("/singleton/")
19+
public class SingletonEndpoint {
20+
21+
@OnOpen
22+
public void onopen(Session s) throws IOException, InterruptedException {
23+
//Thread.currentThread().sleep(1000);
24+
s.getBasicRemote().sendText(String.valueOf(hashCode()));
25+
}
26+
27+
@OnMessage
28+
@Lock(LockType.READ)
29+
public void onmsg(Session s, String msg) throws IOException, InterruptedException {
30+
//Thread.currentThread().sleep(1000);
31+
s.getBasicRemote().sendText("hello client from "+String.valueOf(hashCode()));
32+
}
33+
34+
@PreDestroy
35+
public void onDestroy() {
36+
System.out.println("Singleton bean " + hashCode() + " will be destroyed");
37+
}
38+
39+
@OnClose
40+
public void onClose(Session session, CloseReason closeReason) {
41+
System.out.println("Closed " + session.getId() + " due to " + closeReason.getCloseCode());
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.gitbooks.abhirockzz.jwah.websocketejb;
2+
3+
import java.io.IOException;
4+
5+
import javax.annotation.PreDestroy;
6+
import javax.ejb.Remove;
7+
import javax.ejb.Stateful;
8+
9+
import javax.websocket.CloseReason;
10+
import javax.websocket.OnClose;
11+
import javax.websocket.OnOpen;
12+
import javax.websocket.Session;
13+
import javax.websocket.server.ServerEndpoint;
14+
15+
@Stateful
16+
@ServerEndpoint("/stateful/")
17+
public class StatefulEndpoint {
18+
19+
20+
@OnOpen
21+
public void onOpen(Session s) throws IOException{
22+
s.getBasicRemote().sendText(String.valueOf(hashCode()));
23+
}
24+
25+
@PreDestroy
26+
public void onDestroy(){
27+
System.out.println("Stateful bean "+ hashCode() + " will be destroyed");
28+
}
29+
30+
31+
@OnClose
32+
public void onClose(Session session, CloseReason closeReason) {
33+
System.out.println("Closed " + session.getId() + " due to " + closeReason.getCloseCode());
34+
clear();
35+
}
36+
37+
@Remove
38+
public void clear(){
39+
System.out.println("Removing Stateful bean "+ hashCode());
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package io.gitbooks.abhirockzz.jwah.websocketejb;
2+
3+
import java.io.IOException;
4+
5+
import javax.annotation.PreDestroy;
6+
import javax.ejb.Stateless;
7+
8+
import javax.websocket.CloseReason;
9+
import javax.websocket.OnClose;
10+
import javax.websocket.OnMessage;
11+
import javax.websocket.OnOpen;
12+
import javax.websocket.Session;
13+
import javax.websocket.server.ServerEndpoint;
14+
15+
@Stateless
16+
@ServerEndpoint("/stateless/")
17+
public class StatelessEndpoint {
18+
19+
@OnOpen
20+
public void onopen(Session s) throws IOException, InterruptedException {
21+
/**
22+
* simulate minor delay. helps confirm if additional instance of this bean will be created in
23+
* case concurrent requests come through
24+
*/
25+
Thread.currentThread().sleep(1000);
26+
s.getBasicRemote().sendText(String.valueOf(hashCode()));
27+
}
28+
29+
@OnMessage
30+
public void onmsg(Session s, String msg) throws IOException, InterruptedException {
31+
//Thread.currentThread().sleep(1000);
32+
s.getBasicRemote().sendText("hello client.. my hasCode() is "+String.valueOf(hashCode()));
33+
}
34+
35+
@OnClose
36+
public void onClose(Session session, CloseReason closeReason) {
37+
System.out.println("closed " + session.getId() + " due to " + closeReason.getCloseCode());
38+
}
39+
40+
@PreDestroy
41+
public void onDestroy() {
42+
System.out.println("going to be destroyed...");
43+
}
44+
45+
}

Diff for: application/src/main/webapp/index.html

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Start Page</title>
5+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6+
</head>
7+
<body>
8+
<h1>Hello World!</h1>
9+
</body>
10+
</html>

Diff for: tests/pom.xml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>com.oracle.cloud.accs</groupId>
5+
<artifactId>websocket-ejb-tests</artifactId>
6+
<version>1.0</version>
7+
<packaging>jar</packaging>
8+
<properties>
9+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
10+
<maven.compiler.source>1.8</maven.compiler.source>
11+
<maven.compiler.target>1.8</maven.compiler.target>
12+
</properties>
13+
14+
<dependencies>
15+
<dependency>
16+
<groupId>junit</groupId>
17+
<artifactId>junit</artifactId>
18+
<version>4.12</version>
19+
<scope>test</scope>
20+
</dependency>
21+
<dependency>
22+
<groupId>org.hamcrest</groupId>
23+
<artifactId>hamcrest-core</artifactId>
24+
<version>1.3</version>
25+
<scope>test</scope>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.glassfish.tyrus</groupId>
29+
<artifactId>tyrus-client</artifactId>
30+
<version>1.12</version>
31+
<scope>test</scope>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.glassfish.tyrus</groupId>
35+
<artifactId>tyrus-server</artifactId>
36+
<version>1.12</version>
37+
<scope>test</scope>
38+
</dependency>
39+
40+
</dependencies>
41+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package io.gitbooks.abhirockzz.jwah.websocketejb;
2+
3+
import java.io.IOException;
4+
import java.net.URI;
5+
import java.util.concurrent.CountDownLatch;
6+
import java.util.logging.Level;
7+
import java.util.logging.Logger;
8+
import javax.websocket.ContainerProvider;
9+
import javax.websocket.DeploymentException;
10+
import javax.websocket.Endpoint;
11+
import javax.websocket.Session;
12+
13+
public class ConnectToServer implements Runnable {
14+
15+
Endpoint client;
16+
String serverURL;
17+
CountDownLatch startSignal = null;
18+
CountDownLatch closeConnSignal = null;
19+
Session session = null;
20+
21+
public ConnectToServer(Endpoint client, String serverURL, CountDownLatch startLatch, CountDownLatch closeConnLatch) {
22+
this.client = client;
23+
this.serverURL = serverURL;
24+
this.startSignal = startLatch;
25+
this.closeConnSignal = closeConnLatch;
26+
}
27+
28+
private void waitForStartSignal() throws InterruptedException {
29+
startSignal.await();
30+
}
31+
32+
private void disconnectAfterClose() throws InterruptedException, IOException {
33+
closeConnSignal.await();
34+
session.close();
35+
}
36+
37+
@Override
38+
public void run() {
39+
40+
System.out.println(Thread.currentThread() + " is Q'd");
41+
try {
42+
waitForStartSignal();
43+
} catch (InterruptedException ex) {
44+
Logger.getLogger(WebSocketEJBTest.class.getName()).log(Level.SEVERE, null, ex);
45+
}
46+
try {
47+
this.session = ContainerProvider.getWebSocketContainer()
48+
.connectToServer(client,
49+
URI.create(serverURL));
50+
51+
System.out.println("Session created " + session.getId());
52+
disconnectAfterClose();
53+
54+
} catch (DeploymentException ex) {
55+
Logger.getLogger(WebSocketEJBTest.class.getName()).log(Level.SEVERE, null, ex);
56+
} catch (IOException ex) {
57+
Logger.getLogger(WebSocketEJBTest.class.getName()).log(Level.SEVERE, null, ex);
58+
} catch (InterruptedException ex) {
59+
Logger.getLogger(ConnectToServer.class.getName()).log(Level.SEVERE, null, ex);
60+
}
61+
62+
}
63+
64+
}

0 commit comments

Comments
 (0)