Skip to content
Snippets Groups Projects
Commit 5b8dc87a authored by Sven Kästle's avatar Sven Kästle
Browse files

Merge branch 'annotation_#47-6' into development_master

parents 750e4863 dedcc47e
No related branches found
No related tags found
No related merge requests found
Showing
with 348 additions and 84 deletions
......@@ -165,6 +165,21 @@
<version>1.3.4</version>
</dependency>
<!-- websocket api -->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<!-- gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>com.atlassian.commonmark</groupId>
<artifactId>commonmark</artifactId>
......
package unipotsdam.gf.modules.annotation.model;
public class AnnotationMessage {
// variables
private String from;
private String targetId;
private AnnotationMessageType type;
private String annotationId;
public enum AnnotationMessageType {
GET,
DELETE
}
// methods
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTargetId() {
return targetId;
}
public void setTargetId(String targetId) {
this.targetId = targetId;
}
public AnnotationMessageType getType() {
return type;
}
public void setType(AnnotationMessageType type) {
this.type = type;
}
public String getAnnotationId() {
return annotationId;
}
public void setAnnotationId(String annotationId) {
this.annotationId = annotationId;
}
@Override
public String toString() {
return "AnnotationMessage{" +
"from='" + from + '\'' +
", targetId='" + targetId + '\'' +
", type=" + type +
", annotationId='" + annotationId + '\'' +
'}';
}
}
package unipotsdam.gf.modules.annotation.websocket;
import com.google.gson.Gson;
import unipotsdam.gf.modules.annotation.model.AnnotationMessage;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
public class AnnotationMessageDecoder implements Decoder.Text<AnnotationMessage> {
public static Gson gson = new Gson();
@Override
public AnnotationMessage decode(String s) throws DecodeException {
AnnotationMessage annotationMessage = gson.fromJson(s, AnnotationMessage.class);
return annotationMessage;
}
@Override
public boolean willDecode(String s) {
return (null != s);
}
@Override
public void init(EndpointConfig endpointConfig) {
// todo
}
@Override
public void destroy() {
// todo
}
}
package unipotsdam.gf.modules.annotation.websocket;
import com.google.gson.Gson;
import unipotsdam.gf.modules.annotation.model.AnnotationMessage;
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
public class AnnotationMessageEncoder implements Encoder.Text<AnnotationMessage> {
private static Gson gson = new Gson();
@Override
public String encode(AnnotationMessage annotationMessage) throws EncodeException {
String json = gson.toJson(annotationMessage);
return json;
}
@Override
public void init(EndpointConfig endpointConfig) {
// todo
}
@Override
public void destroy() {
// todo
}
}
package unipotsdam.gf.modules.annotation.websocket;
import unipotsdam.gf.modules.annotation.model.AnnotationMessage;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint(value = "/ws/annotation/{targetId}", decoders = AnnotationMessageDecoder.class, encoders = AnnotationMessageEncoder.class)
public class AnnotationWebSocketEndpoint {
private Session session;
private static final Set<AnnotationWebSocketEndpoint> endpoints = new CopyOnWriteArraySet<>();
private static HashMap<String, String> targets = new HashMap<>();
@OnOpen
public void onOpen(Session session, @PathParam("targetId") String targetId) throws IOException {
// initialize session
this.session = session;
// save endpoint in set of endpoints
endpoints.add(this);
// save mapping of session and target id
targets.put(session.getId(), targetId);
}
@OnMessage
public void onMessage(Session session, AnnotationMessage annotationMessage) throws IOException, EncodeException {
annotationMessage.setTargetId(targets.get(session.getId()));
annotationMessage.setFrom(session.getId());
broadcast(annotationMessage);
}
@OnClose
public void onClose(Session session) throws IOException {
endpoints.remove(this);
}
@OnError
public void onError(Session session, Throwable throwable) {
// todo
}
private void broadcast(AnnotationMessage annotationMessage) throws IOException, EncodeException {
endpoints.forEach(endpoint -> {
synchronized (endpoint) {
try {
if (targets.get(endpoint.session.getId()).equals(annotationMessage.getTargetId())
&& !endpoint.session.getId().equals(annotationMessage.getFrom())) {
System.out.println("Send message to session" + endpoint.session.getId() + " from session " + annotationMessage.getFrom());
endpoint.session.getBasicRemote().sendObject(annotationMessage);
}
}
catch (IOException | EncodeException e) {
e.printStackTrace();
}
}
});
}
}
/**
* POST: Save an annotation in the database
*
* @param annotationPostRequest The post request
* @param responseHandler The response handler
*/
function createAnnotation(annotationPostRequest, responseHandler) {
var url = "../rest/annotations/";
var json = JSON.stringify(annotationPostRequest);
$.ajax({
url: url,
type: "POST",
data: json,
contentType: "application/json",
dataType: "json",
success: function (response) {
responseHandler(response);
}
});
}
/**
* PATCH: Alter an annotation in database
*
* @param id The annotation id
* @param annotationPatchRequest The patch request
* @param responseHandler The response handler
*/
function alterAnnotation(id, annotationPatchRequest, responseHandler) {
var url = "../rest/annotations/" + id;
var json = JSON.stringify(annotationPatchRequest);
$.ajax({
url: url,
type: "PATCH",
data: json,
contentType: "application/json",
dataType: "json",
success: function (response) {
responseHandler(response);
}
});
}
/**
* DELETE: Delete an annotation from database
*
* @param id The annotation id
*/
function deleteAnnotation(id, responseHandler) {
var url = "../rest/annotations/" + id;
$.ajax({
url: url,
type: "DELETE",
dataType: "json",
success: function (response) {
responseHandler(response)
}
});
}
/**
* GET: Get a specific annotation for a given id
*
* @param id The id of the annotation
* @param responseHandler The response handler
*/
function getAnnotation(id, responseHandler) {
var url = "../rest/annotations/" + id;
$.ajax({
url: url,
type: "GET",
dataType: "json",
success: function (response) {
// handle the response
responseHandler(response);
}
})
}
/**
* GET: Get all annotations from database for a specific target
*
* @param targetId The target id
* @param responseHandler The response handler
*/
function getAnnotations(targetId, responseHandler) {
var url = "../rest/annotations/target/" + targetId;
$.ajax({
url: url,
type: "GET",
dataType: "json",
success: function (response) {
// sort the responding annotations by timestamp (DESC)
response.sort(function (a, b) {
return a.timestamp - b.timestamp;
});
// handle the response
responseHandler(response);
}
});
}
\ No newline at end of file
......@@ -12,6 +12,9 @@ var documentText, startCharacter, endCharacter;
*/
$(document).ready(function() {
// connect to websocket on page ready
connect(targetId);
/**
* Context menu handler
*/
......@@ -163,6 +166,8 @@ $(document).ready(function() {
// delte annotation from server and from list
deleteAnnotation(id, function () {
// send delete request to websocket
send("DELETE", id);
// remove annotation from list
$('#' + id).closest('.listelement').remove()
// remove highlighted text
......@@ -215,90 +220,6 @@ $( window ).resize(function() {
showAndHideToggleButton();
});
/**
* POST: Save an annotation in the database
*
* @param annotationPostRequest The post request
* @param responseHandler The response handler
*/
function createAnnotation(annotationPostRequest, responseHandler) {
var url = "../rest/annotations/";
var json = JSON.stringify(annotationPostRequest);
$.ajax({
url: url,
type: "POST",
data: json,
contentType: "application/json",
dataType: "json",
success: function (response) {
responseHandler(response);
}
});
}
/**
* PATCH: Alter an annotation in database
*
* @param id The annotation id
* @param annotationPatchRequest The patch request
* @param responseHandler The response handler
*/
function alterAnnotation(id, annotationPatchRequest, responseHandler) {
var url = "../rest/annotations/" + id;
var json = JSON.stringify(annotationPatchRequest);
$.ajax({
url: url,
type: "PATCH",
data: json,
contentType: "application/json",
dataType: "json",
success: function (response) {
responseHandler(response);
}
});
}
/**
* DELETE: Delete an annotation from database
*
* @param id The annotation id
*/
function deleteAnnotation(id, responseHandler) {
var url = "../rest/annotations/" + id;
$.ajax({
url: url,
type: "DELETE",
dataType: "json",
success: function (response) {
responseHandler(response)
}
});
}
/**
* GET: Get all annotations from database for a specific target
*
*
* @param targetId The target id
* @param responseHandler The response handler
*/
function getAnnotations(targetId, responseHandler) {
var url = "../rest/annotations/target/" + targetId;
$.ajax({
url: url,
type: "GET",
dataType: "json",
success: function (response) {
// sort the responding annotations by timestamp (DESC)
response.sort(function (a, b) {
return a.timestamp - b.timestamp;
});
// handle the response
responseHandler(response);
}
});
}
/**
* Display annotation in the list
*
......@@ -612,6 +533,8 @@ function saveNewAnnotation(title, comment, startCharacter, endCharacter) {
// send new annotation to back-end and display it in list
createAnnotation(annotationPostRequest, function(response) {
// send new annotation to websocket
send("GET", response.id);
// display the new annotation
displayAnnotation(response);
......@@ -659,9 +582,11 @@ function showAndHideToggleButton() {
// show drop down button only if text was truncated
if(cloneWidth > comment.width()) {
$(this).find('.annotation-header-toggle').show();
$(this).find('.annotation-header-data').css('width', 'calc(100% - 40px)');
}
else {
$(this).find('.annotation-header-toggle').hide();
$(this).find('.annotation-header-data').css('width', '100%');
}
})
......
var ws;
function connect(targetId) {
var host = document.location.host;
var pathname = document.location.pathname;
ws = new WebSocket("ws://" + host + "/ws/annotation/" + targetId);
ws.onmessage = function (e) {
var message = JSON.parse(e.data);
console.log(message.from)
if (message.type === "GET") {
// get annotation from server
getAnnotation(message.annotationId, function (response) {
// display annotation
displayAnnotation(response)
})
}
else if (message.type === "DELETE") {
// remove annotation from list
$('#' + message.annotationId).closest('.listelement').remove()
}
};
}
function send(type, annotationId) {
var json = JSON.stringify({
"type":type,
"annotationId":annotationId
})
ws.send(json);
}
\ No newline at end of file
......@@ -34,6 +34,10 @@
<script src="https://swisnl.github.io/jQuery-contextMenu/dist/jquery.contextMenu.js" type="text/javascript"></script>
<!-- js - utility script -->
<script src="../assets/js/utility.js"></script>
<!-- js - annotation websocket script -->
<script src="../assets/js/annotationWebsocket.js"></script>
<!-- js - annotation REST script -->
<script src="../assets/js/annotationRest.js"></script>
<!-- js - annotationScript -->
<script src="../assets/js/annotationScript.js"></script>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment