Skip to content

Commit 26dedbd

Browse files
authored
Merge pull request #44 from vinscom/refector-code-to-better-handle-binary
Added proper handling of binary request and response
2 parents 6daa151 + 2562b63 commit 26dedbd

File tree

11 files changed

+75
-72
lines changed

11 files changed

+75
-72
lines changed

config-layers/test/in/erail/service/BinaryBodyService.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@ serviceUniqueId=API_V1_BROADCAST_V2_SERVICE
66
vertx=/io/vertx/core/Vertx
77
enable=true
88
log=true
9-
bodyAsJson=false

src/main/java/in/erail/common/FrameworkConstants.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ public static class Json {
2222
public static final String STATUS_CODE = "statusCode";
2323
public static final String IS_BASE64_ENCODED = "isBase64Encoded";
2424
}
25-
26-
public static class Attribute {
27-
28-
public static final String BODY_AS_JSON = "bodyAsJson";
29-
}
3025
}
3126

3227
public static class SockJS {

src/main/java/in/erail/route/OpenAPI3RouteBuilder.java

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.codahale.metrics.Metered;
55
import com.codahale.metrics.MetricRegistry;
66
import com.codahale.metrics.Timer;
7-
import com.google.common.base.Strings;
87
import com.google.common.net.HttpHeaders;
98
import com.google.common.net.MediaType;
109
import java.io.File;
@@ -25,6 +24,7 @@
2524
import io.vertx.reactivex.ext.web.RoutingContext;
2625
import io.vertx.reactivex.ext.web.api.contract.openapi3.OpenAPI3RouterFactory;
2726
import in.erail.service.RESTService;
27+
import io.vertx.reactivex.core.buffer.Buffer;
2828
import java.util.Arrays;
2929
import java.util.HashMap;
3030
import java.util.Optional;
@@ -102,28 +102,20 @@ public void process(RoutingContext pRequestContext, String pServiceUniqueId) {
102102

103103
}
104104

105+
/**
106+
* In case of post request. Body is sent in binary
107+
*
108+
* @param pContext Routing Context
109+
* @return JsonObject representing RoutingContext
110+
*/
105111
public JsonObject serialiseRoutingContext(RoutingContext pContext) {
106112

107113
JsonObject result = new JsonObject();
108114

109115
if (pContext.request().method() == HttpMethod.POST) {
110-
boolean bodyAsJson = pContext.<Boolean>get(FrameworkConstants.RoutingContext.Attribute.BODY_AS_JSON);
111-
if (bodyAsJson) {
112-
String mediaTypeHeader = pContext.request().headers().get(HttpHeaders.CONTENT_TYPE);
113-
MediaType contentType;
114-
if (Strings.isNullOrEmpty(mediaTypeHeader)) {
115-
contentType = MediaType.JSON_UTF_8;
116-
} else {
117-
contentType = MediaType.parse(mediaTypeHeader);
118-
}
119-
if (MediaType.JSON_UTF_8.type().equals(contentType.type()) && MediaType.JSON_UTF_8.subtype().equals(contentType.subtype())) {
120-
result.put(FrameworkConstants.RoutingContext.Json.BODY, pContext.getBodyAsJson());
121-
}
122-
} else {
123-
result.put(FrameworkConstants.RoutingContext.Json.BODY, pContext.getBody().getDelegate().getBytes());
124-
}
116+
result.put(FrameworkConstants.RoutingContext.Json.BODY, pContext.getBody().getDelegate().getBytes());
125117
} else {
126-
result.put(FrameworkConstants.RoutingContext.Json.BODY, new JsonObject());
118+
result.put(FrameworkConstants.RoutingContext.Json.BODY, new byte[]{});
127119
}
128120

129121
JsonObject headers = new JsonObject(convertMultiMapIntoMap(pContext.request().headers()));
@@ -140,13 +132,20 @@ public JsonObject serialiseRoutingContext(RoutingContext pContext) {
140132
return result;
141133
}
142134

135+
/**
136+
* All response content is written in binary. If Content type is not provided then application/octet-stream content type is set.
137+
*
138+
* @param pReplyResponse Service Body
139+
* @param pContext Routing Context
140+
* @return HttpServerResponse
141+
*/
143142
public HttpServerResponse buildResponseFromReply(JsonObject pReplyResponse, RoutingContext pContext) {
144143

145144
JsonObject headers = pReplyResponse.getJsonObject(FrameworkConstants.RoutingContext.Json.HEADERS, new JsonObject());
146145
String statusCode = pReplyResponse.getString(FrameworkConstants.RoutingContext.Json.STATUS_CODE, HttpResponseStatus.OK.codeAsText().toString());
147146

148147
if (!headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
149-
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
148+
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.OCTET_STREAM.toString());
150149
}
151150

152151
headers
@@ -158,13 +157,12 @@ public HttpServerResponse buildResponseFromReply(JsonObject pReplyResponse, Rout
158157

159158
pContext.response().setStatusCode(HttpResponseStatus.parseLine(statusCode).code());
160159

161-
Object body = pReplyResponse.getMap().get(FrameworkConstants.RoutingContext.Json.BODY);
160+
Optional<byte[]> body = Optional.ofNullable(pReplyResponse.getBinary(FrameworkConstants.RoutingContext.Json.BODY));
162161

163-
if (body != null) {
164-
String bodyStr = body.toString();
165-
pContext.response().putHeader(HttpHeaderNames.CONTENT_LENGTH.toString(), Integer.toString(bodyStr.length()));
166-
pContext.response().write(bodyStr);
167-
}
162+
body.ifPresent((t) -> {
163+
pContext.response().putHeader(HttpHeaderNames.CONTENT_LENGTH.toString(), Integer.toString(t.length));
164+
pContext.response().write(Buffer.newInstance(io.vertx.core.buffer.Buffer.buffer(t)));
165+
});
168166

169167
return pContext.response();
170168
}
@@ -200,9 +198,6 @@ public Router getRouter(Router pRouter) {
200198
.stream()
201199
.forEach((service) -> {
202200
apiFactory.addHandlerByOperationId(service.getOperationId(), (routingContext) -> {
203-
204-
routingContext.put(FrameworkConstants.RoutingContext.Attribute.BODY_AS_JSON, service.isBodyAsJson());
205-
206201
if (isSecurityEnable()) {
207202

208203
if (routingContext.user() == null) {

src/main/java/in/erail/server/Server.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class Server {
2525
private Logger mLog;
2626
private SockJSHandler mSockJSHandler;
2727
private HttpServerOptions mHttpServerOptions;
28+
private HttpServer mHttpServer;
2829

2930
@StartService
3031
public void start() {
@@ -46,7 +47,7 @@ public void start() {
4647
router.mountSubRouter(mMountPath[i], mRouter[i]);
4748
}
4849

49-
server
50+
mHttpServer = server
5051
.requestHandler(router::accept)
5152
.rxListen()
5253
.blockingGet();
@@ -106,4 +107,12 @@ public void setHttpServerOptions(HttpServerOptions pHttpServerOptions) {
106107
this.mHttpServerOptions = pHttpServerOptions;
107108
}
108109

110+
public HttpServer getHttpServer() {
111+
return mHttpServer;
112+
}
113+
114+
public void setHttpServer(HttpServer pHttpServer) {
115+
this.mHttpServer = pHttpServer;
116+
}
117+
109118
}

src/main/java/in/erail/service/RESTService.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,5 @@
1111
public interface RESTService {
1212
String getOperationId();
1313
String getServiceUniqueId();
14-
boolean isBodyAsJson();
1514
void process(Message<JsonObject> pMessage);
1615
}

src/main/java/in/erail/service/RESTServiceImpl.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
*/
1414
public abstract class RESTServiceImpl implements RESTService {
1515

16-
private boolean mBodyAsJson = true;
1716
private String mOperationId;
1817
private String mServiceUniqueId;
1918
private Vertx mVertx;
@@ -77,14 +76,6 @@ public void setLog(Logger pLog) {
7776
this.mLog = pLog;
7877
}
7978

80-
public boolean isBodyAsJson() {
81-
return mBodyAsJson;
82-
}
83-
84-
public void setBodyAsJson(boolean pBodyAsJson) {
85-
this.mBodyAsJson = pBodyAsJson;
86-
}
87-
8879
public Scheduler getScheduler() {
8980
return mScheduler;
9081
}

src/test/java/in/erail/service/BinaryBodyService.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package in.erail.service;
22

33
import com.google.common.base.Strings;
4-
import in.erail.common.FrameworkConstants;
4+
import com.google.common.net.HttpHeaders;
5+
import com.google.common.net.MediaType;
56
import in.erail.test.TestConstants;
67
import io.vertx.core.buffer.Buffer;
78
import io.vertx.core.json.JsonObject;
89
import io.vertx.reactivex.core.eventbus.Message;
10+
import static in.erail.common.FrameworkConstants.RoutingContext.*;
911

1012
/**
1113
*
@@ -15,17 +17,24 @@ public class BinaryBodyService extends RESTServiceImpl{
1517

1618
@Override
1719
public void process(Message<JsonObject> pMessage) {
18-
JsonObject param = pMessage.body().getJsonObject(FrameworkConstants.RoutingContext.Json.PATH_PARAM);
20+
JsonObject param = pMessage.body().getJsonObject(Json.PATH_PARAM);
1921
String topicName = param.getString(TestConstants.Service.Broadcast.APIMessage.PARAM_TOPIC_NAME);
2022

2123
if(Strings.isNullOrEmpty(topicName)){
2224
pMessage.fail(0, "Empty Topic Name");
2325
}
2426

25-
byte[] body = pMessage.body().getBinary(FrameworkConstants.RoutingContext.Json.BODY);
27+
JsonObject headers = new JsonObject();
28+
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8.toString());
2629

27-
JsonObject resp = new JsonObject(Buffer.buffer(body));
28-
resp.put(FrameworkConstants.RoutingContext.Json.BODY, Integer.toString(body.length));
30+
byte[] body = pMessage.body().getBinary(Json.BODY);
31+
JsonObject jsonBody = new JsonObject(Buffer.buffer(body));
32+
33+
String bodyContent = jsonBody.getString("data");
34+
35+
JsonObject resp = new JsonObject();
36+
resp.put(Json.BODY, bodyContent.getBytes());
37+
resp.put(Json.HEADERS, headers);
2938

3039
pMessage.reply(resp);
3140
}

src/test/java/in/erail/service/BinaryBodyServiceTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package in.erail.service;
22

33
import com.google.common.net.HttpHeaders;
4+
import com.google.common.net.MediaType;
45
import in.erail.server.Server;
56
import in.erail.test.TestConstants;
67
import org.junit.Test;
@@ -13,7 +14,6 @@
1314
import io.vertx.ext.unit.junit.VertxUnitRunner;
1415
import org.junit.Rule;
1516
import in.erail.glue.Glue;
16-
import io.netty.handler.codec.http.HttpHeaderNames;
1717

1818
/**
1919
*
@@ -38,16 +38,16 @@ public void testProcess(TestContext context) {
3838
.getVertx()
3939
.createHttpClient()
4040
.post(server.getHttpServerOptions().getPort(), server.getHttpServerOptions().getHost(), "/v1/broadcastv2/testTopic")
41-
.putHeader("content-type", "application/json")
41+
.putHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString())
4242
.putHeader(HttpHeaders.ORIGIN, "https://test.com")
43-
.putHeader("content-length", Integer.toString(json.length()))
43+
.putHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(json.length()))
4444
.putHeader(HttpHeaders.AUTHORIZATION, TestConstants.ACCESS_TOKEN)
4545
.handler(response -> {
4646
context.assertEquals(response.statusCode(), 200, response.statusMessage());
47-
context.assertEquals(response.getHeader(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString()),"*");
48-
context.assertEquals(response.getHeader(HttpHeaderNames.CONTENT_TYPE.toString()),"application/json; charset=utf-8");
47+
context.assertEquals(response.getHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN),"*");
48+
context.assertTrue(MediaType.parse(response.getHeader(HttpHeaders.CONTENT_TYPE)).equals(MediaType.PLAIN_TEXT_UTF_8));
4949
response.bodyHandler((event) -> {
50-
context.assertEquals(event.toString(), "19");
50+
context.assertEquals(event.toString(), "testdata");
5151
async.countDown();
5252
});
5353
})
Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,46 @@
11
package in.erail.service;
22

33
import com.google.common.base.Strings;
4+
import com.google.common.net.HttpHeaders;
5+
import com.google.common.net.MediaType;
46
import in.erail.common.FrameworkConstants;
57
import in.erail.test.TestConstants;
8+
import io.vertx.core.buffer.Buffer;
69
import io.vertx.core.json.JsonObject;
710
import io.vertx.reactivex.core.eventbus.Message;
11+
import static in.erail.common.FrameworkConstants.RoutingContext.*;
812

913
/**
1014
*
1115
* @author vinay
1216
*/
13-
public class BroadcastService extends RESTServiceImpl{
17+
public class BroadcastService extends RESTServiceImpl {
1418

1519
@Override
1620
public void process(Message<JsonObject> pMessage) {
17-
JsonObject param = pMessage.body().getJsonObject(FrameworkConstants.RoutingContext.Json.PATH_PARAM);
21+
JsonObject param = pMessage.body().getJsonObject(Json.PATH_PARAM);
1822
String topicName = param.getString(TestConstants.Service.Broadcast.APIMessage.PARAM_TOPIC_NAME);
1923

20-
if(Strings.isNullOrEmpty(topicName)){
24+
if (Strings.isNullOrEmpty(topicName)) {
2125
pMessage.fail(0, "Empty Topic Name");
2226
}
2327

24-
JsonObject body = pMessage.body().getJsonObject(FrameworkConstants.RoutingContext.Json.BODY);
25-
28+
byte[] body = pMessage.body().getBinary(FrameworkConstants.RoutingContext.Json.BODY);
29+
JsonObject bodyJson = new JsonObject(Buffer.buffer(body));
30+
2631
getVertx()
2732
.eventBus()
28-
.publish(topicName, body);
29-
30-
getLog().debug(() -> String.format("Message[%s] published on [%s]", body.toString(),topicName));
31-
33+
.publish(topicName, bodyJson);
34+
35+
getLog().debug(() -> String.format("Message[%s] published on [%s]", bodyJson.toString(), topicName));
36+
3237
JsonObject resp = new JsonObject();
33-
resp.put(FrameworkConstants.RoutingContext.Json.BODY, TestConstants.Service.Message.successMessage());
38+
resp.put(Json.BODY, TestConstants.Service.Message.successMessage().toString().getBytes());
39+
40+
JsonObject headers = new JsonObject().put(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
41+
resp.put(Json.HEADERS, headers);
3442

3543
pMessage.reply(resp);
3644
}
37-
45+
3846
}

src/test/java/in/erail/service/BroadcastServiceTest.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import io.vertx.ext.unit.junit.VertxUnitRunner;
1515
import org.junit.Rule;
1616
import in.erail.glue.Glue;
17-
import io.netty.handler.codec.http.HttpHeaderNames;
1817

1918
/**
2019
*
@@ -46,14 +45,14 @@ public void testProcess(TestContext context) {
4645
.getVertx()
4746
.createHttpClient()
4847
.post(server.getHttpServerOptions().getPort(), server.getHttpServerOptions().getHost(), "/v1/broadcast/testTopic")
49-
.putHeader("content-type", MediaType.JSON_UTF_8.toString())
48+
.putHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString())
5049
.putHeader(HttpHeaders.ORIGIN, "https://test.com")
51-
.putHeader("content-length", Integer.toString(json.length()))
50+
.putHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(json.length()))
5251
.putHeader(HttpHeaders.AUTHORIZATION, TestConstants.ACCESS_TOKEN)
5352
.handler(response -> {
5453
context.assertEquals(response.statusCode(), 200, response.statusMessage());
55-
context.assertEquals(response.getHeader(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString()),"*");
56-
context.assertEquals(response.getHeader(HttpHeaderNames.CONTENT_TYPE.toString()),"application/json; charset=utf-8");
54+
context.assertEquals(response.getHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN), "*");
55+
context.assertTrue(MediaType.parse(response.getHeader(HttpHeaders.CONTENT_TYPE)).equals(MediaType.JSON_UTF_8));
5756
response.bodyHandler((event) -> {
5857
context.assertEquals(event.toString(), TestConstants.Service.Message.successMessage().toString());
5958
async.countDown();

0 commit comments

Comments
 (0)