Skip to content

Commit

Permalink
Add a sample for Atmosphere/atmosphere#2510
Browse files Browse the repository at this point in the history
  • Loading branch information
jfarcand committed Jul 16, 2024
1 parent 1c64ad3 commit bbc3cf2
Show file tree
Hide file tree
Showing 12 changed files with 9,294 additions and 4 deletions.
8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,18 @@
</profiles>
<modules>
<module>samples/chat</module>
<module>samples/embedded-jetty-websocket-chat</module>

</modules>
<properties>
<client-version>3.1.0</client-version>
<nettosphere-version>4.0.0</nettosphere-version>
<atmosphere-version>3.0.5</atmosphere-version>
<extensions-version>3.0.0</extensions-version>
<extensions-version>3.0.8</extensions-version>
<jetty-version>12.0.11</jetty-version>
<websocket-version>2.0.0</websocket-version>
<wasync-version>2.1.2</wasync-version>
<logback-version>1.4.14</logback-version>
<jackson-version>2.16.1</jackson-version>
</properties>
</project>
6 changes: 3 additions & 3 deletions samples/chat/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
<version>${logback-version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.4.14</version>
<version>${logback-version}</version>
</dependency>
<dependency>
<groupId>org.atmosphere</groupId>
Expand All @@ -43,7 +43,7 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.1</version>
<version>${jackson-version}</version>
</dependency>
</dependencies>
<properties>
Expand Down
1 change: 1 addition & 0 deletions samples/embedded-jetty-websocket-chat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/bin
7 changes: 7 additions & 0 deletions samples/embedded-jetty-websocket-chat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## To Run the sample

Run the following maven commands.

mvn install
mvn -Pserver

139 changes: 139 additions & 0 deletions samples/embedded-jetty-websocket-chat/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<parent>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-samples-project</artifactId>
<version>3.0.2-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.atmosphere.samples</groupId>
<artifactId>atmosphere-jetty-embedded-websocket</artifactId>
<packaging>jar</packaging>
<version>3.0.2-SNAPSHOT</version>
<name>atmosphere-jetty-embedded-websocket</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback-version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback-version}</version>
</dependency>
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-runtime</artifactId>
<version>${atmosphere-version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-servlet</artifactId>
<version>${jetty-version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty-version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty-version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
<artifactId>jetty-ee10-websocket-jakarta-server</artifactId>
<version>${jetty-version}</version>
</dependency>
<dependency>
<groupId>jakarta.websocket</groupId>
<artifactId>jakarta.websocket-api</artifactId>
<version>${websocket-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-version}</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>server</id>
<build>
<defaultGoal>test</defaultGoal>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.atmosphere.samples.chat.EmbeddedJettyWebSocketChat</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.atmosphere.client</groupId>
<artifactId>javascript</artifactId>
<version>${client-version}</version>
<type>war</type>
<overWrite>true</overWrite>
<outputDirectory>${basedir}/target/webapp</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/webapp</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/webapp</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.atmosphere.samples.chat;

import org.eclipse.jetty.ee10.servlet.DefaultServlet;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.atmosphere.cpr.ApplicationConfig;
import org.atmosphere.cpr.AtmosphereServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;

public class EmbeddedJettyWebSocketChat {
private static final Logger log = LoggerFactory.getLogger(EmbeddedJettyWebSocketChat.class);

public static void main(String[] args) throws Exception {
new EmbeddedJettyWebSocketChat().run();
}

private void run() throws Exception {
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");

Path resourceBasePath = Paths.get("/Users/jeanfrancoisarcand/workspace/w_atmopshere/atmosphere-samples/samples/embedded-jetty-websocket-chat/target/webapp");
context.setBaseResource(ResourceFactory.root().newResource(resourceBasePath.toUri()));

// Add DefaultServlet to serve static content
ServletHolder defaultServlet = new ServletHolder("default", DefaultServlet.class);
defaultServlet.setInitParameter("dirAllowed", "true");
defaultServlet.setInitParameter("welcomeServlets", "true");
defaultServlet.setInitParameter("redirectWelcome", "true");
context.addServlet(defaultServlet, "/*");

// Add AtmosphereServlet
ServletHolder atmosphereServlet = new ServletHolder(AtmosphereServlet.class);
atmosphereServlet.setInitParameter(ApplicationConfig.ANNOTATION_PACKAGE, "org.atmosphere.samples.chat");
atmosphereServlet.setInitParameter(ApplicationConfig.WEBSOCKET_CONTENT_TYPE, "application/json");
atmosphereServlet.setAsyncSupported(true);
context.addServlet(atmosphereServlet, "/chat/*");

// Configure WebSocket
JakartaWebSocketServletContainerInitializer.configure(context, null);

server.setHandler(context);

log.info("Resource base: {}", context.getBaseResource());
log.info("Resource base exists: {}", context.getBaseResource().exists());
Path indexPath = resourceBasePath.resolve("index.html");
log.info("index.html exists: {}", Files.exists(indexPath));
if (Files.exists(indexPath)) {
log.info("index.html content:\n{}", Files.readString(indexPath));
} else {
log.warn("index.html not found at {}", indexPath);
}
log.info("Default servlet path spec: /*");
log.info("Atmosphere servlet path spec: /chat/*");
log.info("WebSocket support added");

server.start();
log.info("Server started on port {}", connector.getPort());
server.join();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright 2008-2022 Async-IO.org
*
* 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.atmosphere.samples.chat;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.atmosphere.config.service.WebSocketHandlerService;
import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.atmosphere.util.SimpleBroadcaster;
import org.atmosphere.websocket.WebSocket;
import org.atmosphere.websocket.WebSocketEventListenerAdapter;
import org.atmosphere.websocket.WebSocketHandler;
import org.atmosphere.websocket.WebSocketStreamingHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Date;

/**
* Simple {@link WebSocketHandler} that implement the logic to build a Chat application.
*
* @author Jeanfrancois Arcand
*/
@WebSocketHandlerService(path = "/chat", broadcaster = SimpleBroadcaster.class,
atmosphereConfig = {"org.atmosphere.websocket.WebSocketProtocol=org.atmosphere.websocket.protocol.StreamingHttpProtocol"})
public class WebSocketChat extends WebSocketStreamingHandlerAdapter {

private final Logger logger = LoggerFactory.getLogger(WebSocketChat.class);
private final ObjectMapper mapper = new ObjectMapper();

@Override
public void onOpen(WebSocket webSocket) throws IOException {
webSocket.resource().addEventListener(new WebSocketEventListenerAdapter() {
@Override
public void onDisconnect(AtmosphereResourceEvent event) {
if (event.isCancelled()) {
logger.info("Browser {} unexpectedly disconnected", event.getResource().uuid());
} else if (event.isClosedByClient()) {
logger.info("Browser {} closed the connection", event.getResource().uuid());
}
}
});
}

public void onTextStream(WebSocket webSocket, Reader reader) {
try {
webSocket.broadcast(mapper.writeValueAsString(mapper.readValue(new BufferedReader(reader).readLine(), Data.class)));
} catch (Exception e) {
logger.error("Failed to parse JSON", e);
}
}

public final static class Data {

private String message;
private String author;
private long time;

public Data() {
this("", "");
}

public Data(String author, String message) {
this.author = author;
this.message = message;
this.time = new Date().getTime();
}

public String getMessage() {
return message;
}

public String getAuthor() {
return author;
}

public void setAuthor(String author) {
this.author = author;
}

public void setMessage(String message) {
this.message = message;
}

public long getTime() {
return time;
}

public void setTime(long time) {
this.time = time;
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<configuration debug='true'>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>

<logger name="org.atmosphere" level="DEBUG"/>
<root>
<level value="INFO"/>
<appender-ref ref="STDOUT"/>
</root>

</configuration>
Loading

0 comments on commit bbc3cf2

Please sign in to comment.