diff --git a/java-websocket/pom.xml b/java-websocket/pom.xml
new file mode 100644
index 0000000000..929e6491fd
--- /dev/null
+++ b/java-websocket/pom.xml
@@ -0,0 +1,41 @@
+
+ 4.0.0
+ com.baeldung
+ java-websocket
+ war
+ 0.0.1-SNAPSHOT
+ java-websocket Maven Webapp
+ http://maven.apache.org
+
+
+ UTF-8
+
+
+
+
+ javax.websocket
+ javax.websocket-api
+ 1.1
+
+
+ com.google.code.gson
+ gson
+ 2.8.0
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.5.1
+
+ 1.8
+ 1.8
+
+
+
+
+
diff --git a/java-websocket/src/main/java/com/baeldung/model/Message.java b/java-websocket/src/main/java/com/baeldung/model/Message.java
new file mode 100644
index 0000000000..3d5bbcbc5d
--- /dev/null
+++ b/java-websocket/src/main/java/com/baeldung/model/Message.java
@@ -0,0 +1,36 @@
+package com.baeldung.model;
+
+public class Message {
+ private String from;
+ private String to;
+ private String content;
+
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ public String getTo() {
+ return to;
+ }
+
+ public void setTo(String to) {
+ this.to = to;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+}
diff --git a/java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java b/java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java
new file mode 100644
index 0000000000..c4e20f4b27
--- /dev/null
+++ b/java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java
@@ -0,0 +1,71 @@
+package com.baeldung.websocket;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import javax.websocket.EncodeException;
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+
+import com.baeldung.model.Message;
+
+@ServerEndpoint(value = "/chat/{username}", decoders = MessageDecoder.class, encoders = MessageEncoder.class)
+public class ChatEndpoint {
+ private Session session;
+ private static final Set chatEndpoints = new CopyOnWriteArraySet<>();
+ private static HashMap users = new HashMap<>();
+
+ @OnOpen
+ public void onOpen(Session session, @PathParam("username") String username) throws IOException, EncodeException {
+
+ this.session = session;
+ chatEndpoints.add(this);
+ users.put(session.getId(), username);
+
+ Message message = new Message();
+ message.setFrom(username);
+ message.setContent("Connected!");
+ broadcast(message);
+ }
+
+ @OnMessage
+ public void onMessage(Session session, Message message) throws IOException, EncodeException {
+ message.setFrom(users.get(session.getId()));
+ broadcast(message);
+ }
+
+ @OnClose
+ public void onClose(Session session) throws IOException, EncodeException {
+ chatEndpoints.remove(this);
+ Message message = new Message();
+ message.setFrom(users.get(session.getId()));
+ message.setContent("Disconnected!");
+ broadcast(message);
+ }
+
+ @OnError
+ public void onError(Session session, Throwable throwable) {
+ // Do error handling here
+ }
+
+ private static void broadcast(Message message) throws IOException, EncodeException {
+ chatEndpoints.forEach(endpoint -> {
+ synchronized (endpoint) {
+ try {
+ endpoint.session.getBasicRemote()
+ .sendObject(message);
+ } catch (IOException | EncodeException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+}
diff --git a/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java b/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java
new file mode 100644
index 0000000000..29ae5b93e6
--- /dev/null
+++ b/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java
@@ -0,0 +1,32 @@
+package com.baeldung.websocket;
+
+import javax.websocket.DecodeException;
+import javax.websocket.Decoder;
+import javax.websocket.EndpointConfig;
+
+import com.baeldung.model.Message;
+import com.google.gson.Gson;
+
+public class MessageDecoder implements Decoder.Text {
+ @Override
+ public Message decode(String s) throws DecodeException {
+ Gson gson = new Gson();
+ Message message = gson.fromJson(s, Message.class);
+ return message;
+ }
+
+ @Override
+ public boolean willDecode(String s) {
+ return (s != null);
+ }
+
+ @Override
+ public void init(EndpointConfig endpointConfig) {
+ // Custom initialization logic
+ }
+
+ @Override
+ public void destroy() {
+ // Close resources
+ }
+}
diff --git a/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java b/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java
new file mode 100644
index 0000000000..bfecc87a96
--- /dev/null
+++ b/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java
@@ -0,0 +1,27 @@
+package com.baeldung.websocket;
+
+import javax.websocket.EncodeException;
+import javax.websocket.Encoder;
+import javax.websocket.EndpointConfig;
+
+import com.baeldung.model.Message;
+import com.google.gson.Gson;
+
+public class MessageEncoder implements Encoder.Text {
+ @Override
+ public String encode(Message message) throws EncodeException {
+ Gson gson = new Gson();
+ String json = gson.toJson(message);
+ return json;
+ }
+
+ @Override
+ public void init(EndpointConfig endpointConfig) {
+ // Custom initialization logic
+ }
+
+ @Override
+ public void destroy() {
+ // Close resources
+ }
+}
diff --git a/java-websocket/src/main/webapp/WEB-INF/beans.xml b/java-websocket/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000000..73cd0d8e10
--- /dev/null
+++ b/java-websocket/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/java-websocket/src/main/webapp/WEB-INF/web.xml b/java-websocket/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..9f88c1f963
--- /dev/null
+++ b/java-websocket/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,7 @@
+
+
+
+ Archetype Created Web Application
+
diff --git a/java-websocket/src/main/webapp/index.html b/java-websocket/src/main/webapp/index.html
new file mode 100644
index 0000000000..2b76fb1e49
--- /dev/null
+++ b/java-websocket/src/main/webapp/index.html
@@ -0,0 +1,30 @@
+
+
+ Chat
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java-websocket/src/main/webapp/style.css b/java-websocket/src/main/webapp/style.css
new file mode 100644
index 0000000000..ec0982005a
--- /dev/null
+++ b/java-websocket/src/main/webapp/style.css
@@ -0,0 +1,136 @@
+body {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 80%;
+ background-color: #1f1f1f;
+}
+
+#wrapper {
+ width: 960px;
+ margin: auto;
+ text-align: left;
+ color: #d9d9d9;
+}
+
+p {
+ text-align: left;
+}
+
+.button {
+ display: inline;
+ color: #fff;
+ background-color: #f2791d;
+ padding: 8px;
+ margin: auto;
+ border-radius: 8px;
+ -moz-border-radius: 8px;
+ -webkit-border-radius: 8px;
+ box-shadow: none;
+ border: none;
+}
+
+.button:hover {
+ background-color: #ffb15e;
+}
+.button a, a:visited, a:hover, a:active {
+ color: #fff;
+ text-decoration: none;
+}
+
+#addDevice {
+ text-align: center;
+ width: 960px;
+ margin: auto;
+ margin-bottom: 10px;
+}
+
+#addDeviceForm {
+ text-align: left;
+ width: 400px;
+ margin: auto;
+ padding: 10px;
+}
+
+#addDeviceForm span {
+ display: block;
+}
+
+#content {
+ margin: auto;
+ width: 960px;
+}
+
+.device {
+ width: 180px;
+ height: 110px;
+ margin: 10px;
+ padding: 16px;
+ color: #fff;
+ vertical-align: top;
+ border-radius: 8px;
+ -moz-border-radius: 8px;
+ -webkit-border-radius: 8px;
+ display: inline-block;
+}
+
+.device.off {
+ background-color: #c8cccf;
+}
+
+.device span {
+ display: block;
+}
+
+.deviceName {
+ text-align: center;
+ font-weight: bold;
+ margin-bottom: 12px;
+}
+
+.removeDevice {
+ margin-top: 12px;
+ text-align: center;
+}
+
+.device.Appliance {
+ background-color: #5eb85e;
+}
+
+.device.Appliance a:hover {
+ color: #a1ed82;
+}
+
+.device.Electronics {
+ background-color: #0f90d1;
+}
+
+.device.Electronics a:hover {
+ color: #4badd1;
+}
+
+.device.Lights {
+ background-color: #c2a00c;
+}
+
+.device.Lights a:hover {
+ color: #fad232;
+}
+
+.device.Other {
+ background-color: #db524d;
+}
+
+.device.Other a:hover {
+ color: #ff907d;
+}
+
+.device a {
+ text-decoration: none;
+}
+
+.device a:visited, a:active, a:hover {
+ color: #fff;
+}
+
+.device a:hover {
+ text-decoration: underline;
+}
\ No newline at end of file
diff --git a/java-websocket/src/main/webapp/websocket.js b/java-websocket/src/main/webapp/websocket.js
new file mode 100644
index 0000000000..39e5687f0c
--- /dev/null
+++ b/java-websocket/src/main/webapp/websocket.js
@@ -0,0 +1,23 @@
+var ws;
+
+function connect() {
+ var username = document.getElementById("username").value;
+ ws = new WebSocket("ws://" + document.location.host + "/java-websocket/chat/" + username);
+
+
+ ws.onmessage = function(event) {
+ var log = document.getElementById("log");
+ console.log(event.data);
+ var message = JSON.parse(event.data);
+ log.innerHTML += message.from + " : " + message.content + "\n";
+ };
+}
+
+function send() {
+ var content = document.getElementById("msg").value;
+ var json = JSON.stringify({
+ "content":content
+ });
+
+ ws.send(json);
+}
\ No newline at end of file