Skip to content

Instantly share code, notes, and snippets.

@rybalkinsd
Last active June 3, 2021 17:18
Show Gist options
  • Save rybalkinsd/73b83901afc0c12d77ba65cb219eeb21 to your computer and use it in GitHub Desktop.
Save rybalkinsd/73b83901afc0c12d77ba65cb219eeb21 to your computer and use it in GitHub Desktop.
Simple chat. Jersey + Jetty + Html +Js
package ru.atom.http.server;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.util.ConcurrentArrayQueue;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
@Path("/")
public class ChatResource {
private static final Logger log = LogManager.getLogger(ChatResource.class);
private static final ConcurrentArrayQueue<String> logined = new ConcurrentArrayQueue<>();
private static final ConcurrentArrayQueue<String> chat = new ConcurrentArrayQueue<>();
@POST
@Consumes("application/x-www-form-urlencoded")
@Path("/login")
public Response login(@QueryParam("name") String name) {
if (name.length() < 1) {
return Response.status(Response.Status.BAD_REQUEST).entity("Too short name, sorry :(").build();
}
if (name.length() > 30) {
return Response.status(Response.Status.BAD_REQUEST).entity("Too long name, sorry :(").build();
}
if (name.toLowerCase().contains("gitler")) {
return Response.status(Response.Status.BAD_REQUEST).entity("Gitler not allowed, sorry :(").build();
}
if (logined.contains(name)) {
return Response.status(Response.Status.BAD_REQUEST).entity("Already logined").build();
}
log.info("[" + name + "] logined");
logined.add(name);
chat.add("[" + name + "] joined");
return Response.ok().build();
}
@GET
@Produces("text/plain")
@Path("/online")
public Response online() {
return Response.ok(String.join("\n", logined)).build();
}
@POST
@Consumes("application/x-www-form-urlencoded")
@Path("/say")
public Response say(@QueryParam("name") String name, @FormParam("msg") String msg) {
if (name == null) {
return Response.status(Response.Status.UNAUTHORIZED).entity("Name not provided").build();
}
if (!logined.contains(name)) {
return Response.status(Response.Status.UNAUTHORIZED).entity("Not logined").build();
}
if (msg == null) {
return Response.status(Response.Status.BAD_REQUEST).entity("No message provided").build();
}
if (msg.length() > 140) {
return Response.status(Response.Status.BAD_REQUEST).entity("Too long message").build();
}
log.info("[" + name + "]: " + msg);
chat.add("[" + name + "]: " + msg);
return Response.ok().build();
}
@GET
@Produces("text/plain")
@Path("/chat")
public Response chat() {
return Response.ok(String.join("\n", chat)).build();
}
}
package ru.atom.http.server;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
@Provider
public class CrossBrowserFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}
package ru.atom.http.server;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public class HttpServer {
public static void main(String[] args) throws Exception {
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[] {
createChatContext(),
createResourceContext()
});
Server jettyServer = new Server(8080);
jettyServer.setHandler(contexts);
jettyServer.start();
}
private static ServletContextHandler createChatContext() {
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/chat/*");
ServletHolder jerseyServlet = context.addServlet(
org.glassfish.jersey.servlet.ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
jerseyServlet.setInitParameter(
"jersey.config.server.provider.packages",
"ru.atom.http"
);
jerseyServlet.setInitParameter(
"com.sun.jersey.spi.container.ContainerResponseFilters",
CrossBrowserFilter.class.getCanonicalName()
);
return context;
}
private static ContextHandler createResourceContext() {
ContextHandler context = new ContextHandler();
context.setContextPath("/");
ResourceHandler handler = new ResourceHandler();
handler.setWelcomeFiles(new String[]{"index.html"});
String serverRoot = HttpServer.class.getResource("/static").toString();
System.out.println(serverRoot);
handler.setResourceBase(serverRoot);
context.setHandler(handler);
return context;
}
}
<script>
var host = "localhost";
var port = 8080;
</script>
<html>
<style>
:root {
background: #336666;
}
.chat {
background: #99CCCC;
font-family: "Courier New", Courier, monospace;
padding: 7px;
margin: 0 0 1em;
overflow: auto;
}
.form {
height: 85%;
}
.msginput {
width: 80%;
}
.sendbutton {
width: 15%;
}
#header {
background: #336666;
padding: 10px;
padding-bottom: 0;
}
#body {
padding: 10px;
padding-top: 0;
padding-bottom: 30px; /* Height of the footer */
}
#footer {
padding: 10px;
position: absolute;
bottom: 0;
width: 100%;
height: 30px; /* Height of the footer */
background: #336666;
}
</style>
<body>
<div id="header">
<form method="POST" id="nameform" action="javascript:void(null);" onsubmit="login()">
<input id="name" name="name" value="" style="font-size:medium" type="text">
<input value="Login" style="font-size:large" type="submit">
</form>
</div>
<div id="body">
<div id="history" class="chat form"></div>
</div>
<div id="footer">
<form method="POST" id="msgform" action="javascript:void(null);" onsubmit="say()">
<input id="msg" name="msg" class="msginput" value="" style="font-size:medium" type="text">
<input value="Send" class="sendbutton" style="font-size:large" type="submit">
</form>
</div>
</body>
</html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
function loadHistory() {
var settings = {
"crossDomain": true,
"url": "http://" + host + ":" + port + "/chat/chat",
"method": "GET",
}
$.ajax(settings).done(function (response) {
$( "#history" ).html(response.replace(/\n/g, "<br />"))
$( "#history" ).scrollTop( $( "#history" )[0].scrollHeight );
}).fail(function (jqXHR, textStatus) {
console.log(jqXHR.status + " " + jqXHR.statusText + ". " + jqXHR.responseText);
});
}
setInterval(loadHistory, 1000);
</script>
<script>
function say() {
var msg = $('#msgform').serialize();
var name = $('#nameform').serialize();
var settings = {
"method": "POST",
"crossDomain": true,
"url": "http://" + host + ":" + port + "/chat/say?"+name,
"data": msg
}
$.ajax(settings).done(function(response) {
$('#msgform').trigger("reset");
loadHistory();
}).fail(function (jqXHR, textStatus) {
alert(jqXHR.status + " " + jqXHR.statusText + ". " + jqXHR.responseText);
console.log(jqXHR.status + " " + jqXHR.statusText + ". " + jqXHR.responseText);
});
}
</script>
<script>
function login() {
var name = $('#nameform').serialize();
var settings = {
"method": "POST",
"crossDomain": true,
"url": "http://" + host + ":" + port + "/chat/login?"+name,
}
$.ajax(settings).done(function(response) {
loadHistory();
}).fail(function (jqXHR, textStatus) {
alert(jqXHR.status + " " + jqXHR.statusText + ". " + jqXHR.responseText);
console.log(jqXHR.status + " " + jqXHR.statusText + ". " + jqXHR.responseText);
});
}
</script>
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %m%n
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment