Skip to content

Commit 1f2d9d7

Browse files
committed
PLUGIN-1936: Initial Commit
1 parent 42846e3 commit 1f2d9d7

File tree

3 files changed

+88
-6
lines changed

3 files changed

+88
-6
lines changed

src/main/java/io/cdap/plugin/servicenow/apiclient/ServiceNowTableAPIClientImpl.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@
2525
import com.google.common.base.Strings;
2626
import com.google.gson.Gson;
2727
import com.google.gson.JsonArray;
28+
import com.google.gson.JsonElement;
2829
import com.google.gson.JsonObject;
2930
import com.google.gson.reflect.TypeToken;
31+
import com.google.gson.stream.JsonReader;
32+
import com.google.gson.stream.JsonToken;
3033
import io.cdap.cdap.api.data.schema.Schema;
3134
import io.cdap.cdap.etl.api.FailureCollector;
3235
import io.cdap.plugin.servicenow.connector.ServiceNowConnectorConfig;
@@ -55,8 +58,12 @@
5558
import org.slf4j.LoggerFactory;
5659

5760
import java.io.IOException;
61+
import java.io.InputStream;
62+
import java.io.InputStreamReader;
5863
import java.lang.reflect.Type;
64+
import java.nio.charset.StandardCharsets;
5965
import java.util.ArrayList;
66+
import java.util.HashMap;
6067
import java.util.List;
6168
import java.util.Map;
6269
import java.util.Objects;
@@ -154,7 +161,9 @@ public List<Map<String, String>> fetchTableRecords(
154161
String accessToken = getAccessToken();
155162
requestBuilder.setAuthHeader(accessToken);
156163
RestAPIResponse apiResponse = executeGetWithRetries(requestBuilder.build());
157-
return parseResponseToResultListOfMap(apiResponse.getResponseBody());
164+
//return parseResponseToResultListOfMap(apiResponse.getResponseBody());
165+
return parseResponseStreamToResultListOfMap(apiResponse.getInputStream());
166+
158167
}
159168

160169
private void applyDateRangeToRequest(ServiceNowTableAPIRequestBuilder requestBuilder, String startDate,
@@ -197,6 +206,43 @@ public List<Map<String, String>> parseResponseToResultListOfMap(String responseB
197206
return GSON.fromJson(ja, type);
198207
}
199208

209+
public List<Map<String, String>> parseResponseStreamToResultListOfMap(InputStream in) throws ServiceNowAPIException {
210+
List<Map<String, String>> records = new ArrayList<>();
211+
// InputStream in = httpResponse.getEntity().getContent();
212+
try (InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
213+
JsonReader jsonReader = new JsonReader(reader)) {
214+
jsonReader.setLenient(true);
215+
jsonReader.beginObject();
216+
while (jsonReader.hasNext()) {
217+
String name = jsonReader.nextName();
218+
if (ServiceNowConstants.RESULT.equals(name) && jsonReader.peek() == JsonToken.BEGIN_ARRAY) {
219+
jsonReader.beginArray();
220+
while (jsonReader.hasNext()) {
221+
jsonReader.beginObject();
222+
Map<String, String> record = new HashMap<>();
223+
while (jsonReader.hasNext()) {
224+
String field = jsonReader.nextName();
225+
JsonToken token = jsonReader.peek();
226+
// JsonElement resultElement = GSON.fromJson(jsonReader, JsonElement.class);
227+
// responseBody = resultElement.toString();
228+
record.put(field, token == JsonToken.NULL ? null : jsonReader.nextString());
229+
}
230+
jsonReader.endObject();
231+
records.add(record);
232+
}
233+
jsonReader.endArray();
234+
} else {
235+
// skip other fields (e.g., metadata like result_count)
236+
jsonReader.skipValue();
237+
}
238+
}
239+
jsonReader.endObject();
240+
return records;
241+
} catch (IOException e) {
242+
throw new ServiceNowAPIException(e, null);
243+
}
244+
}
245+
200246
private String getErrorMessage(String responseBody) {
201247
try {
202248
JsonObject jo = GSON.fromJson(responseBody, JsonObject.class);

src/main/java/io/cdap/plugin/servicenow/restapi/RestAPIClient.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.slf4j.LoggerFactory;
4444

4545
import java.io.IOException;
46+
import java.io.InputStream;
4647
import java.net.SocketException;
4748
import java.util.Collections;
4849
import java.util.concurrent.Callable;
@@ -82,7 +83,7 @@ public RestAPIResponse executeGet(RestAPIRequest request) throws IOException {
8283
}
8384
} catch (ConnectTimeoutException | SocketException e) {
8485
ServiceNowAPIException exception = new ServiceNowAPIException(e, null);
85-
return new RestAPIResponse(Collections.emptyMap(), null, exception);
86+
return new RestAPIResponse(Collections.emptyMap(), (InputStream) null, exception);
8687
}
8788
}
8889

src/main/java/io/cdap/plugin/servicenow/restapi/RestAPIResponse.java

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,28 @@
1717
package io.cdap.plugin.servicenow.restapi;
1818

1919
import com.google.gson.Gson;
20+
import com.google.gson.JsonElement;
2021
import com.google.gson.JsonObject;
22+
import com.google.gson.stream.JsonReader;
2123
import io.cdap.plugin.servicenow.apiclient.ServiceNowAPIException;
2224
import io.cdap.plugin.servicenow.util.ServiceNowConstants;
2325
import org.apache.http.Header;
26+
import org.apache.http.HttpEntity;
2427
import org.apache.http.HttpResponse;
2528
import org.apache.http.HttpStatus;
2629
import org.apache.http.util.EntityUtils;
2730

2831
import java.io.IOException;
32+
import java.io.InputStream;
33+
import java.io.InputStreamReader;
34+
import java.nio.charset.StandardCharsets;
2935
import java.util.Arrays;
3036
import java.util.Collections;
3137
import java.util.HashMap;
3238
import java.util.HashSet;
3339
import java.util.List;
3440
import java.util.Map;
41+
import java.util.Optional;
3542
import java.util.Set;
3643
import java.util.stream.Collectors;
3744
import javax.annotation.Nullable;
@@ -46,9 +53,14 @@ public class RestAPIResponse {
4653
private static final Set<Integer> SUCCESS_CODES = new HashSet<>(Arrays.asList(HttpStatus.SC_CREATED,
4754
HttpStatus.SC_OK));
4855
private final Map<String, String> headers;
49-
private final String responseBody;
56+
// Deprecated: storing full body as String can cause OOM
57+
@Deprecated
58+
private String responseBody;
5059
@Nullable private final ServiceNowAPIException exception;
5160

61+
// New: store InputStream for streaming consumption
62+
private InputStream inputStream;
63+
5264
public RestAPIResponse(
5365
Map<String, String> headers,
5466
@Nullable String responseBody,
@@ -58,6 +70,15 @@ public RestAPIResponse(
5870
this.exception = exception;
5971
}
6072

73+
public RestAPIResponse(
74+
Map<String, String> headers,
75+
InputStream inputStream,
76+
@Nullable ServiceNowAPIException exception) {
77+
this.headers = headers;
78+
this.inputStream = inputStream;
79+
this.exception = exception;
80+
}
81+
6182
/**
6283
* Parses HttpResponse into RestAPIResponse object when no errors occur.
6384
* Throws a {@link ServiceNowAPIException}.
@@ -80,17 +101,27 @@ public static RestAPIResponse parse(HttpResponse httpResponse, String... headerN
80101

81102
ServiceNowAPIException serviceNowAPIException = validateHttpResponse(httpResponse);
82103
if (serviceNowAPIException != null) {
83-
return new RestAPIResponse(headers, null, serviceNowAPIException);
104+
return new RestAPIResponse(headers, (InputStream) null, serviceNowAPIException);
84105
}
85106

86107
String responseBody = null;
87108
try {
88109
responseBody = EntityUtils.toString(httpResponse.getEntity());
89110
} catch (IOException e) {
90-
return new RestAPIResponse(headers, null, new ServiceNowAPIException(e, httpResponse));
111+
return new RestAPIResponse(headers, (String) null, new ServiceNowAPIException(e, httpResponse));
112+
}
113+
// Instead of reading the entire entity, store the stream
114+
HttpEntity httpEntity = httpResponse.getEntity();
115+
InputStream responseStream;
116+
try {
117+
responseStream = (httpEntity != null) ? httpEntity.getContent() : null;
118+
} catch (IOException e) {
119+
return new RestAPIResponse(headers, (InputStream) null, new ServiceNowAPIException(e, httpResponse));
91120
}
92121
serviceNowAPIException = validateRestApiResponse(httpResponse, responseBody);
93-
return new RestAPIResponse(headers, responseBody, serviceNowAPIException);
122+
// return new RestAPIResponse(headers, responseBody, serviceNowAPIException);
123+
return new RestAPIResponse(headers, responseStream, serviceNowAPIException);
124+
94125
}
95126

96127
public static RestAPIResponse parse(HttpResponse httpResponse) throws IOException {
@@ -131,6 +162,10 @@ public String getResponseBody() {
131162
return responseBody;
132163
}
133164

165+
public InputStream getInputStream() {
166+
return inputStream;
167+
}
168+
134169
@Nullable
135170
public ServiceNowAPIException getException() {
136171
return exception;

0 commit comments

Comments
 (0)