Skip to content

Commit 9a3ea84

Browse files
Refactor LaraClient Streaming Internals and Unify Stream Handling (#4)
* Refactor LaraClient Streaming Internals and Unify Stream Handling * Remove debug print
1 parent 640334c commit 9a3ea84

3 files changed

Lines changed: 91 additions & 125 deletions

File tree

src/main/java/com/translated/lara/net/ClientResponse.java

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import com.google.gson.JsonObject;
66
import com.google.gson.JsonParser;
77
import com.translated.lara.errors.LaraApiConnectionException;
8-
import com.translated.lara.errors.LaraApiException;
98
import com.translated.lara.errors.LaraApiConnectionTimeoutException;
9+
import com.translated.lara.errors.LaraApiException;
1010

1111
import java.io.BufferedReader;
1212
import java.io.IOException;
@@ -28,8 +28,8 @@ public class ClientResponse {
2828
private final String rawData;
2929
private final String contentType;
3030

31-
ClientResponse(Gson gson, HttpURLConnection connection) throws LaraApiConnectionException {
32-
this.gson = gson;
31+
static ClientResponse fromConnection(Gson gson, HttpURLConnection connection) throws LaraApiConnectionException {
32+
String contentType = connection.getContentType();
3333

3434
int httpStatus;
3535
try {
@@ -42,20 +42,15 @@ public class ClientResponse {
4242

4343
boolean isSuccessful = httpStatus >= 200 && httpStatus < 300;
4444

45-
this.contentType = connection.getContentType();
46-
4745
if (isSuccessful && contentType != null && contentType.contains("text/csv")) {
4846
try (BufferedReader reader = new BufferedReader(
4947
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
50-
this.rawData = reader.lines().collect(Collectors.joining("\n"));
51-
this.data = null;
52-
this.error = null;
48+
String csvBody = reader.lines().collect(Collectors.joining("\n"));
49+
return new ClientResponse(gson, contentType, csvBody);
5350
} catch (IOException e) {
5451
throw new LaraApiConnectionException("Failed to get response stream", e);
5552
}
5653
} else {
57-
this.rawData = null;
58-
5954
JsonElement response;
6055
try (Reader reader = new InputStreamReader(isSuccessful ? connection.getInputStream() : connection.getErrorStream(), StandardCharsets.UTF_8)) {
6156
JsonObject root = JsonParser.parseReader(reader).getAsJsonObject();
@@ -64,27 +59,43 @@ public class ClientResponse {
6459
throw new LaraApiConnectionException("Failed to get response stream", e);
6560
}
6661

67-
if (isSuccessful) {
68-
this.error = null;
69-
this.data = response;
70-
} else {
71-
String type = "UnknownError";
72-
String message = "An unknown error occurred";
73-
74-
if (response != null) {
75-
JsonObject error = response.getAsJsonObject();
76-
if (error.has("type"))
77-
type = error.get("type").getAsString();
78-
if (error.has("message"))
79-
message = error.get("message").getAsString();
80-
}
81-
82-
this.error = new LaraApiException(httpStatus, type, message);
83-
this.data = null;
62+
return new ClientResponse(gson, httpStatus, contentType, response);
63+
}
64+
}
65+
66+
ClientResponse(Gson gson, int httpStatus, String contentType, JsonElement response) {
67+
this.gson = gson;
68+
this.contentType = contentType;
69+
this.rawData = null;
70+
71+
if (httpStatus >= 200 && httpStatus < 300) {
72+
this.error = null;
73+
this.data = response;
74+
} else {
75+
String type = "UnknownError";
76+
String message = "An unknown error occurred";
77+
78+
if (response != null) {
79+
JsonObject error = response.getAsJsonObject();
80+
if (error.has("type"))
81+
type = error.get("type").getAsString();
82+
if (error.has("message"))
83+
message = error.get("message").getAsString();
8484
}
85+
86+
this.error = new LaraApiException(httpStatus, type, message);
87+
this.data = null;
8588
}
8689
}
8790

91+
ClientResponse(Gson gson, String contentType, String csvBody) {
92+
this.gson = gson;
93+
this.contentType = contentType;
94+
this.rawData = csvBody;
95+
this.data = null;
96+
this.error = null;
97+
}
98+
8899
public <T> T as(Class<T> clazz) throws LaraApiException {
89100
if (error != null) throw error;
90101
return gson.fromJson(data, clazz);

src/main/java/com/translated/lara/net/LaraClient.java

Lines changed: 27 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
package com.translated.lara.net;
22

3-
import com.google.gson.FieldNamingPolicy;
4-
import com.google.gson.Gson;
5-
import com.google.gson.GsonBuilder;
6-
import com.google.gson.JsonElement;
7-
import com.google.gson.JsonObject;
8-
import com.google.gson.JsonParser;
3+
import com.google.gson.*;
94
import com.translated.lara.Credentials;
105
import com.translated.lara.Version;
116
import com.translated.lara.errors.LaraApiConnectionException;
12-
import com.translated.lara.errors.LaraApiException;
137
import com.translated.lara.errors.LaraException;
148
import com.translated.lara.net.json.DocumentStatusTypeAdapter;
159
import com.translated.lara.net.json.TextResultValueTypeAdapter;
@@ -18,12 +12,7 @@
1812

1913
import javax.crypto.Mac;
2014
import javax.crypto.spec.SecretKeySpec;
21-
import java.io.BufferedReader;
22-
import java.io.File;
23-
import java.io.IOException;
24-
import java.io.InputStream;
25-
import java.io.InputStreamReader;
26-
import java.io.OutputStream;
15+
import java.io.*;
2716
import java.net.HttpURLConnection;
2817
import java.net.MalformedURLException;
2918
import java.net.URL;
@@ -133,17 +122,19 @@ public ClientResponse put(String path, Map<String, Object> params, Map<String, F
133122
return request("PUT", path, params, files, headers);
134123
}
135124

136-
public Stream<TextResult> postAndGetStream(String path, Map<String, Object> params) throws LaraException {
125+
public Stream<ClientResponse> postAndGetStream(String path, Map<String, Object> params) throws LaraException {
137126
return postAndGetStream(path, params, null, null);
138127
}
139-
public Stream<TextResult> postAndGetStream(String path, Map<String, Object> params, Map<String, String> headers) throws LaraException {
128+
129+
public Stream<ClientResponse> postAndGetStream(String path, Map<String, Object> params, Map<String, String> headers) throws LaraException {
140130
return postAndGetStream(path, params, null, headers);
141131
}
142-
public Stream<TextResult> postAndGetStream(String path, Map<String, Object> params, Map<String, File> files, Map<String, String> headers) throws LaraException {
143-
return requestStream("POST", path, params, files, headers).map(this::parseTextResult);
132+
133+
public Stream<ClientResponse> postAndGetStream(String path, Map<String, Object> params, Map<String, File> files, Map<String, String> headers) throws LaraException {
134+
return requestStream("POST", path, params, files, headers);
144135
}
145136

146-
private Stream<JsonElement> requestStream(String method, String path, Map<String, Object> params, Map<String, File> files, Map<String, String> headers) throws LaraException {
137+
private Stream<ClientResponse> requestStream(String method, String path, Map<String, Object> params, Map<String, File> files, Map<String, String> headers) throws LaraException {
147138
path = normalizePath(path);
148139
params = prune(params);
149140
files = prune(files);
@@ -210,21 +201,22 @@ private Stream<JsonElement> requestStream(String method, String path, Map<String
210201
throw new LaraApiConnectionException("HTTP error code: " + responseCode);
211202
}
212203

204+
String contentType = connection.getContentType();
213205
InputStream inputStream = connection.getInputStream();
214206
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
215207

216208
return reader.lines()
217-
.filter(line -> !line.trim().isEmpty())
218-
.map(line -> parseStreamLine(line, responseCode))
219-
.onClose(() -> {
220-
try {
221-
reader.close();
222-
} catch (IOException e) {
223-
// Ignore close errors
224-
} finally {
225-
connection.disconnect();
226-
}
227-
});
209+
.filter(line -> !line.trim().isEmpty())
210+
.map(line -> parseStreamLine(contentType, responseCode, line))
211+
.onClose(() -> {
212+
try {
213+
reader.close();
214+
} catch (IOException e) {
215+
// Ignore close errors
216+
} finally {
217+
connection.disconnect();
218+
}
219+
});
228220

229221
} catch (IOException e) {
230222
throw new LaraApiConnectionException("Streaming request failed: " + e.getMessage(), e);
@@ -285,7 +277,7 @@ private ClientResponse request(String method, String path, Map<String, Object> p
285277
}
286278
}
287279

288-
return new ClientResponse(gson, connection);
280+
return ClientResponse.fromConnection(gson, connection);
289281
} catch (IOException e) {
290282
throw new LaraApiConnectionException("Failed to connect to URL: " + baseUrl + path, e);
291283
}
@@ -358,56 +350,13 @@ private TextResult parseTextResult(JsonElement jsonElement) {
358350
}
359351
}
360352

361-
private JsonElement parseStreamLine(String line, int responseCode) {
362-
JsonElement jsonElement;
363-
try {
364-
jsonElement = JsonParser.parseString(line);
365-
} catch (Exception e) {
366-
throw new RuntimeException("Failed to parse streaming response line: " + line, e);
367-
}
368-
369-
if (!jsonElement.isJsonObject()) {
370-
return jsonElement;
371-
}
372-
373-
JsonObject jsonObject = jsonElement.getAsJsonObject();
374-
int status = jsonObject.has("status") ? jsonObject.get("status").getAsInt() : responseCode;
375-
376-
if (status < 200 || status >= 300) {
377-
throw new RuntimeException(buildStreamingApiException(status, jsonObject));
378-
}
379-
380-
JsonElement data = jsonObject.has("data") ? jsonObject.get("data") : jsonElement;
353+
private ClientResponse parseStreamLine(String contentType, int responseCode, String line) {
354+
JsonObject root = JsonParser.parseString(line).getAsJsonObject();
381355

382-
if (data.isJsonObject()) {
383-
JsonObject dataObject = data.getAsJsonObject();
384-
if (dataObject.has("content")) {
385-
return dataObject.get("content");
386-
}
387-
}
388-
389-
return data;
390-
}
391-
392-
private LaraApiException buildStreamingApiException(int status, JsonElement data) {
393-
String type = "UnknownError";
394-
String message = "An unknown error occurred";
395-
396-
if (data != null && data.isJsonObject()) {
397-
JsonObject dataObject = data.getAsJsonObject();
398-
JsonObject errorObject = dataObject.has("error") && dataObject.get("error").isJsonObject()
399-
? dataObject.getAsJsonObject("error")
400-
: dataObject;
401-
402-
if (errorObject.has("type")) {
403-
type = errorObject.get("type").getAsString();
404-
}
405-
if (errorObject.has("message")) {
406-
message = errorObject.get("message").getAsString();
407-
}
408-
}
356+
int httpStatus = root.has("status") ? root.get("status").getAsInt() : responseCode;
357+
JsonElement response = root.has("content") ? root.get("content") : root.get("error");
409358

410-
return new LaraApiException(status, type, message);
359+
return new ClientResponse(gson, httpStatus, contentType, response);
411360
}
412361

413362
// Helper method to read the error stream

0 commit comments

Comments
 (0)