Skip to content

Commit

Permalink
Merge pull request #6 from gprodriguez/master
Browse files Browse the repository at this point in the history
Merge
  • Loading branch information
abmiguez authored May 29, 2019
2 parents db1f368 + 8825270 commit 7c61bf4
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 53 deletions.
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
## Dummy Server in Java ##
The code provided in this Github page is an Annotation Server prototype built in Java language.

The Dummy Server is designed to help researchers and developers to build a simply system in order to listen and respond BeCalm requests as quickly as possible, during the TIPS task in the BioCreative V.5 competition.
The Dummy Server is designed to help researchers and developers to build a simply system in order to listen and respond
BeCalm requests as quickly as possible, during the TIPS task in the BioCreative V.5 competition. This example is done using only Java Sockets, so
it is recommended the implementation of a more complete and specific solution like
[HTTPServer](https://docs.oracle.com/javase/8/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/package-summary.html "HTTPServer"),
[NanoHTTPD](https://github.com/NanoHttpd/nanohttpd "NanoHTTPD") or
[Jetty](https://www.eclipse.org/jetty/ "Jetty").

### Glossary ###
* [BioCreative V.5 competition](https://biocreative.bioinformatics.udel.edu/resources/publications/bcv5_proceedings "BioCreative V.5 competition")
Expand All @@ -17,8 +22,13 @@ Clone the repository and make a JAR (select the main class Server) or simply dow

`java [-Xmx2G] [-Xms256M] -server -jar dummyserver.jar`

Note that, the parameters between brackets are optional. However, it may be interesting to modify the maximum memory allocation and the initial memory allocation pool when starting the JVM (-Xmx and -Xms, respectively).
Note that, the parameters between brackets are optional. However, it may be interesting to modify the maximum memory allocation and the initial memory allocation pool when starting the JVM (`-Xmx` and `-Xms`, respectively).

Once the Annotation Server is running, it will be possible to make requests! At this point, you have two options to test the dummy server:

1. If you clone the code and open it in a IDE, you will see a JUnit test to make this requests automatically. To do this, you must execute the Server class first. This JUnit test will send random requests to test the `getState` and `getAnnotations` methods.
2. You can send POST requests to `127.0.0.1:8088` to test the `getState` method. The requests must be in JSON format and it is mandatory to use the correct `becalm_key`. See the following example:
`curl -H "Content-Type: application/json" -X POST http://127.0.0.1:8088 -d "{\"name\": \"BeCalm\",\"method\": \"getState\",\"becalm_key\": \"b907e0df6bbc124844ae97dea98d3d0fc059c133\",\"custom_parameters\": {\"example\": true},\"parameters\": {}}"`

Once the Annotation Server is running, it will be possible to make requests! If you clone the code and open it in a IDE, you will see a JUnit test to make this requests automatically. To do this, you must execute the Server class first.
### License ###
Copyright © 2019, Aitor Blanco Míguez. Released under the Unlicense license.
39 changes: 39 additions & 0 deletions src/main/java/es/uvigo/ei/sing/dummyserver/Functions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package es.uvigo.ei.sing.dummyserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;

public class Functions {
public static String parseRequest(BufferedReader in) {
StringBuilder requestJson = new StringBuilder();

try {
// Read the headers
String headerLine;
while (!(headerLine = in.readLine()).isEmpty()) {
// TODO: Do something with the headers...
}

// Read the body (JSON)
while (in.ready()) {
// TODO: Do some content validations...
requestJson.append((char) in.read());
}
} catch (IOException e) {
e.printStackTrace();
}

return requestJson.toString();
}

public static void writeHeadersAndMessage(PrintWriter out, String message) {
// TODO: Add the desired headers...
out.println("POST HTTP/1.1");
out.println("Content-Length:" + message.length());
out.println("Content-Type: application/json; charset=utf-8");
out.println("");
out.println(message);
out.flush();
}
}
2 changes: 1 addition & 1 deletion src/main/java/es/uvigo/ei/sing/dummyserver/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static void main(String[] args) throws IOException {
// Keep listening until a request is received
while (listening)
new ServerThread(serverSocket.accept()).start();
System.out.println("server> Server stoped");
System.out.println("server> Server stopped");

serverSocket.close();
}
Expand Down
57 changes: 29 additions & 28 deletions src/main/java/es/uvigo/ei/sing/dummyserver/ServerThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;

import static es.uvigo.ei.sing.dummyserver.Constants.REQUEST_SECRET_KEY;
Expand All @@ -18,7 +17,6 @@
@SuppressWarnings("restriction")
public class ServerThread extends Thread {
private Socket socket;
private Socket requestSocket;

public ServerThread(Socket socket) {
super("ServerThread");
Expand All @@ -30,11 +28,12 @@ public void run() {
// Get the CPU state
final OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();

// Get the request
final ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
// Create the output stream to send the response
final PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
out.flush();
final ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
final String clientRequest = (String) in.readObject();
// Get the request (JSON format)
final BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
final String clientRequest = Functions.parseRequest(in);

// Transform the request to a JSON
final JSONObject json = new JSONObject(clientRequest);
Expand All @@ -55,62 +54,63 @@ public void run() {
message = "{\"status\": 200, \"success\": true, \"becalm_key\":\"" + REST_API_KEY + "\", \"data\": {" +
"\"state\":\"" + state + "\", \"version\":\"4.4.3\", \"version_changes\":\"Description of changes\", " +
"\"max_analyzable_documents\":\"515\"} }";
out.writeObject(message);
out.flush();
Functions.writeHeadersAndMessage(out, message);
break;
case "getAnnotations":
// TODO: getAnnotations method. Do something...

message = "{\"status\": 200, \"success\": true, \"becalm_key\":\"" + REST_API_KEY + "\", \"data\": {} }";
out.writeObject(message);
out.flush();
Functions.writeHeadersAndMessage(out, message);
Thread.sleep(2000);
// Send an example annotation
annottatePatents().exceptionally(err -> {
annotatePatents().exceptionally(err -> {
System.out.println("Error while getting annotations: " + err);
return null;
});
break;
default:
// TODO: Invalid method. Do something...
message = "{\"status\": 500, \"success\": false, \"becalm_key\":\"" + REST_API_KEY + "\", \"data\": {} }";
out.writeObject(message);
out.flush();
Functions.writeHeadersAndMessage(out, message);
break;
}
} else {
// Bad key
message = "{\"status\": 401, \"success\": false, \"becalm_key\":\"" + REST_API_KEY + "\", \"data\": {} }";
out.writeObject(message);
out.flush();
Functions.writeHeadersAndMessage(out, message);
}
System.out.println("server> " + message);

// Close resources
in.close();
out.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}

private CompletableFuture<Void> annottatePatents() {
private CompletableFuture<Void> annotatePatents() {
// TODO: Method to make the annotations on the text... This only writes a dummy annotation
return runAsync(() -> {
final String annotations = "[ {\"document_id\": \"CA2073855C\", \"section\": \"T\", \"init\": 0, " +
"\"end\": 14, \"score\": 0.856016, \"annotated_text\": \"Glycoalkaloids\"," +
" \"type\": \"unknown\", \"database_id\": \"ED5266\" } ]";
ObjectInputStream in = null;
ObjectOutputStream out = null;
BufferedReader in = null;
PrintWriter out = null;
Socket requestSocket = null;

try {
requestSocket = new Socket("localhost", Constants.REQUESTERPORT);
System.out.println("server> Connected to localhost in port 8089");
out = new ObjectOutputStream(requestSocket.getOutputStream());
out = new PrintWriter(new OutputStreamWriter(requestSocket.getOutputStream(), StandardCharsets.UTF_8));
out.flush();
requestSocket.setSoTimeout(5000);
in = new ObjectInputStream(requestSocket.getInputStream());
in = new BufferedReader(new InputStreamReader(requestSocket.getInputStream()));

System.out.println("server> " + annotations);

out.writeObject(annotations);
out.flush();
Functions.writeHeadersAndMessage(out, annotations);
int tries = 0;
boolean exit = false;
do {
Expand All @@ -128,26 +128,27 @@ private CompletableFuture<Void> annottatePatents() {
try {
in.close();
out.close();
requestSocket.close();
if (requestSocket != null)
requestSocket.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
});
}

private boolean resendAnnotations(ObjectInputStream in, int tries) {
private boolean resendAnnotations(BufferedReader in, int tries) {
try {
System.out.println("server> Send annotations, try: " + tries);
String ok = (String) in.readObject();
String ok = in.readLine();
final JSONObject json = new JSONObject(ok);
if (json.getInt("status") == 200) {
System.out.println("client> " + ok);
return true;
} else {
return false;
}
} catch (ClassNotFoundException | IOException | JSONException e) {
} catch (IOException | JSONException e) {
return false;
}
}
Expand Down
35 changes: 14 additions & 21 deletions src/test/java/es/uvigo/ei/sing/dummyserver/Requester.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

import junit.framework.TestCase;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Random;
import java.util.concurrent.CompletableFuture;

Expand All @@ -17,8 +16,8 @@
public class Requester extends TestCase {
private ServerSocket serverSocket;
private Socket requestSocket;
private ObjectOutputStream out;
private ObjectInputStream in;
private PrintWriter out;
private BufferedReader in;

public void testRequest() {
boolean listening = true;
Expand All @@ -34,7 +33,7 @@ public void testRequest() {
while (listening)
new ClientThread(serverSocket.accept()).start();

System.out.println("server> Server stoped");
System.out.println("server> Server stopped");

serverSocket.close();
} catch (IOException e) {
Expand All @@ -44,15 +43,15 @@ public void testRequest() {
assertTrue(true);
}

private CompletableFuture<Void> request() throws IOException {
private CompletableFuture<Void> request() {
return runAsync(() -> {
try {
requestSocket = new Socket("localhost", SERVERPORT);
System.out.println("client> Connected to localhost in port " + SERVERPORT);

out = new ObjectOutputStream(requestSocket.getOutputStream());
out = new PrintWriter(new OutputStreamWriter(requestSocket.getOutputStream(), StandardCharsets.UTF_8));
out.flush();
in = new ObjectInputStream(requestSocket.getInputStream());
in = new BufferedReader(new InputStreamReader(requestSocket.getInputStream()));

// Use a random value to request one of the two methods
final Random random = new Random();
Expand All @@ -61,19 +60,15 @@ private CompletableFuture<Void> request() throws IOException {
method = "getAnnotations";
final String petition = "{\"name\":\"BeCalm\", \"method\":\"" + method + "\", \"becalm_key\":\"" + REQUEST_SECRET_KEY + "\"," +
"\"custom_parameters\" :{\"example\":true}, \"parameters\" : {} }";
out.writeObject(petition);
out.flush();
Functions.writeHeadersAndMessage(out, petition);

System.out.println("client> " + petition);

System.out.println("server> " + (String) in.readObject());

System.out.println("server> " + Functions.parseRequest(in));
} catch (UnknownHostException unknownHost) {
System.err.println("client> You are trying to connect to an unknown host!");
} catch (IOException ioException) {
ioException.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
in.close();
Expand All @@ -96,15 +91,13 @@ public ClientThread(Socket socket) {

public void run() {
try {
final ObjectOutputStream out = new ObjectOutputStream(this.socket.getOutputStream());
final PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
out.flush();
final ObjectInputStream in = new ObjectInputStream(this.socket.getInputStream());
System.out.println("server> " + (String) in.readObject());
final BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("server> " + Functions.parseRequest(in));
final String ok = "{\"status\": 200, \"success\": true, \"becalm_key\":\"" + REQUEST_SECRET_KEY + "\", \"data\": {} }";
out.writeObject(ok);
out.flush();
Functions.writeHeadersAndMessage(out, ok);
System.out.println("client> " + ok);

} catch (Exception e) {
e.printStackTrace();
}
Expand Down

0 comments on commit 7c61bf4

Please sign in to comment.