Skip to content

Commit a0e2ca8

Browse files
ssambasuMarkLogic Builder
authored andcommitted
Throw HTTP 400 in case of plugin errors
1 parent 0aa32a1 commit a0e2ca8

File tree

4 files changed

+109
-6
lines changed

4 files changed

+109
-6
lines changed

marklogic-data-hub/src/main/java/com/marklogic/hub/flow/impl/FlowRunnerImpl.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.fasterxml.jackson.databind.JsonNode;
2020
import com.fasterxml.jackson.databind.ObjectMapper;
2121
import com.marklogic.client.DatabaseClient;
22+
import com.marklogic.client.FailedRequestException;
2223
import com.marklogic.client.datamovement.*;
2324
import com.marklogic.client.datamovement.impl.JobTicketImpl;
2425
import com.marklogic.client.extensions.ResourceManager;
@@ -34,7 +35,9 @@
3435
import com.marklogic.hub.job.Job;
3536
import com.marklogic.hub.job.JobManager;
3637
import com.marklogic.hub.job.JobStatus;
38+
import org.apache.commons.lang3.StringUtils;
3739

40+
import java.io.IOException;
3841
import java.io.PrintWriter;
3942
import java.io.StringWriter;
4043
import java.util.*;
@@ -369,7 +372,8 @@ public RunFlowResponse run(String jobId, String[] items) {
369372
}
370373

371374
public RunFlowResponse run(String jobId, String[] items, Map<String, Object> options) {
372-
RunFlowResponse resp;
375+
RunFlowResponse resp = null;
376+
ObjectMapper objectMapper = new ObjectMapper();
373377
try {
374378
RequestParameters params = new RequestParameters();
375379
params.add("entity-name", flow.getEntityName());
@@ -378,7 +382,6 @@ public RunFlowResponse run(String jobId, String[] items, Map<String, Object> opt
378382
params.put("identifiers", items);
379383
params.put("target-database", targetDatabase);
380384
if (options != null) {
381-
ObjectMapper objectMapper = new ObjectMapper();
382385
params.put("options", objectMapper.writeValueAsString(options));
383386
}
384387
ResourceServices.ServiceResultIterator resultItr = this.getServices().post(params, new StringHandle("{}").withFormat(Format.JSON));
@@ -389,7 +392,6 @@ public RunFlowResponse run(String jobId, String[] items, Map<String, Object> opt
389392
else {
390393
ResourceServices.ServiceResult res = resultItr.next();
391394
StringHandle handle = new StringHandle();
392-
ObjectMapper objectMapper = new ObjectMapper();
393395
resp = objectMapper.readValue(res.getContent(handle).get(), RunFlowResponse.class);
394396
}
395397
}
@@ -400,10 +402,25 @@ public RunFlowResponse run(String jobId, String[] items, Map<String, Object> opt
400402
}
401403
}
402404
catch(Exception e) {
403-
e.printStackTrace();
404-
throw new RuntimeException(e);
405+
resp = handleFlowRunnerException (e);
405406
}
406407
return resp;
407408
}
408409
}
410+
411+
protected RunFlowResponse handleFlowRunnerException (Exception e) {
412+
ObjectMapper objectMapper = new ObjectMapper();
413+
RunFlowResponse resp = null;
414+
if(e instanceof FailedRequestException && StringUtils.containsIgnoreCase(((FailedRequestException) e).getFailedRequest().getStatus(), "Plugin error")){
415+
try {
416+
resp = objectMapper.readValue(((FailedRequestException)e).getFailedRequest().getMessage(), RunFlowResponse.class);
417+
} catch (IOException ex) {
418+
throw new RuntimeException("Unexpected IO error while parsing exception from running flow; original exception: " + e.getMessage());
419+
}
420+
}
421+
else{
422+
throw new RuntimeException(e);
423+
}
424+
return resp;
425+
}
409426
}

marklogic-data-hub/src/main/resources/ml-modules/root/data-hub/4/extensions/flow.xqy

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ declare function post(
157157
then trace:error-trace($item-context, $batch-error, xdmp:elapsed-time() - $before)
158158
else trace:error-trace($item-context, $ex, xdmp:elapsed-time() - $before)
159159
}
160-
let $resp :=
160+
let $output :=
161161
document {
162162
object-node {
163163
"totalCount": fn:count($identifiers),
@@ -167,6 +167,11 @@ declare function post(
167167
"errors": $errors
168168
}
169169
}
170+
let $resp :=
171+
if (trace:get-error-count() > 0) then
172+
fn:error((),"RESTAPI-SRVEXERR", (400, "Plugin error", text{$output}))
173+
else
174+
$output
170175
return
171176
$resp
172177
else

marklogic-data-hub/src/main/resources/ml-modules/root/data-hub/4/extensions/sjsflow.sjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ function post(context, params, input) {
120120
"failedItems": tracelib.getFailedItems(),
121121
"errors": errors
122122
}
123+
if(resp.errorCount > 0){
124+
fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([400, "Plugin error", resp]));
125+
}
123126
}
124127
else {
125128
resp = 'error';
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.marklogic.hub.flow.impl;
2+
3+
import com.marklogic.bootstrap.Installer;
4+
import com.marklogic.client.FailedRequestException;
5+
import com.marklogic.client.impl.FailedRequest;
6+
import com.marklogic.hub.ApplicationConfig;
7+
import com.marklogic.hub.HubTestBase;
8+
import com.marklogic.hub.flow.RunFlowResponse;
9+
import org.custommonkey.xmlunit.XMLUnit;
10+
11+
import org.junit.jupiter.api.AfterAll;
12+
import org.junit.jupiter.api.Assertions;
13+
import org.junit.jupiter.api.BeforeEach;
14+
import org.junit.jupiter.api.Test;
15+
import org.junit.jupiter.api.extension.ExtendWith;
16+
import org.springframework.test.context.ContextConfiguration;
17+
import org.springframework.test.context.junit.jupiter.SpringExtension;
18+
19+
import java.io.IOException;
20+
@ExtendWith(SpringExtension.class)
21+
@ContextConfiguration(classes = ApplicationConfig.class)
22+
class FlowRunnerImplTest extends HubTestBase {
23+
@BeforeEach
24+
public void setup() throws IOException {
25+
XMLUnit.setIgnoreWhitespace(true);
26+
createProjectDir();
27+
getDataHubAdminConfig();
28+
}
29+
30+
@AfterAll
31+
public static void cleanup() throws IOException {
32+
new Installer().teardownProject();
33+
}
34+
@Test
35+
public void testFlowRunnerException() {
36+
RunFlowResponse resp = null;
37+
FlowRunnerImpl fr = new FlowRunnerImpl(adminHubConfig);
38+
FailedRequest req = new FailedRequest();
39+
req.setMessageCode("RESTAPI-SRVEXERR");
40+
req.setMessageString("{\n" +
41+
"\t\"totalCount\": 3,\n" +
42+
"\t\"errorCount\": 3,\n" +
43+
"\t\"completedItems\": [],\n" +
44+
"\t\"failedItems\": [\"/10287.json\", \"/10310.json\", \"/10328.json\"],\n" +
45+
"\t\"errors\": []\n" +
46+
"}");
47+
req.setStatusString("Plugin error");
48+
49+
resp = fr.handleFlowRunnerException(new FailedRequestException("failed to apply resource at resources/ml:flow: Plugin error", req));
50+
Assertions.assertEquals(3, resp.errorCount);
51+
Assertions.assertEquals(3, resp.totalCount);
52+
}
53+
54+
@Test
55+
public void testFlowRunnerExceptionWithoutPluginError() {
56+
RunFlowResponse resp = null;
57+
FlowRunnerImpl fr = new FlowRunnerImpl(adminHubConfig);
58+
FailedRequest req = new FailedRequest();
59+
req.setMessageCode("RESTAPI-SRVEXERR");
60+
req.setMessageString("{\n" +
61+
"\t\"totalCount\": 3,\n" +
62+
"\t\"errorCount\": 3,\n" +
63+
"\t\"completedItems\": [],\n" +
64+
"\t\"failedItems\": [\"/10287.json\", \"/10310.json\", \"/10328.json\"],\n" +
65+
"\t\"errors\": []\n" +
66+
"}");
67+
req.setStatusString("Failed");
68+
try {
69+
fr.handleFlowRunnerException(new FailedRequestException("Not a 'Plugin error' exception", req));
70+
}
71+
catch (Exception e) {
72+
Assertions.assertTrue(e instanceof RuntimeException);
73+
e.printStackTrace();
74+
System.out.println(e.getMessage());
75+
Assertions.assertTrue(e.getMessage().contains("com.marklogic.client.FailedRequestException: Local message: Not a 'Plugin error' exception"));
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)