int errorCode = ((RestLiResponseException) exc).getStatus(); if (NON_RETRIABLE_ERRORS.contains(errorCode)) { nonRetriableFail(exc, "Encountered non retriable error. HTTP response code: " + errorCode);
private static <K, RT extends RecordTemplate> Response<RT> unbatchResponse(BatchGetEntityRequest<K, RT> request, Response<BatchKVResponse<K, EntityResponse<RT>>> batchResponse, Object id) throws RemoteInvocationException { final BatchKVResponse<K, EntityResponse<RT>> batchEntity = batchResponse.getEntity(); final ErrorResponse errorResponse = batchEntity.getErrors().get(id); if (errorResponse != null) { throw new RestLiResponseException(errorResponse); } final EntityResponse<RT> entityResponse = batchEntity.getResults().get(id); if (entityResponse != null) { final RT entityResult = entityResponse.getEntity(); if (entityResult != null) { return new ResponseImpl<>(batchResponse, entityResult); } } LOGGER.debug("No result or error for base URI : {}, id: {}. Verify that the batchGet endpoint returns response keys that match batchGet request IDs.", request.getBaseUriTemplate(), id); throw NOT_FOUND_EXCEPTION; }
try { if (error instanceof RestLiResponseException && ((RestLiResponseException) error).getStatus() == HttpStatus.S_301_MOVED_PERMANENTLY.getCode()) { this.redirects++; if (this.redirects >= 5) { String newUri = (String) responseExc.getErrorDetails().get("Location"); RedirectAwareRestClientRequestSender.this.updateRestClient( SharedRestClientFactory.resolveUriPrefix(new URI(newUri)), "301 redirect");
@SuppressWarnings("unchecked") private Response<T> createResponseFromError(RestLiResponseException restLiResponseException) throws RemoteInvocationException { Response<T> response = null; // If the exception contains a decoded response, we use it. Otherwise we do manual response // creation which will not have an entity. if (restLiResponseException.hasDecodedResponse()) { response = new ResponseImpl<T>( (Response<T>) restLiResponseException.getDecodedResponse(), restLiResponseException); } else { response = new ResponseImpl<T>( restLiResponseException.getStatus(), restLiResponseException.getResponse().getHeaders(), CookieUtil.decodeSetCookies(restLiResponseException.getResponse().getCookies()), restLiResponseException); } return response; }
@Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append(getClass().getName()).append(": Response status "); // This is the HTTP status code of the response builder.append(getResponse().getStatus()); // The Rest.li error details may contain an error message from the server, an error code // from the server if (hasServiceErrorMessage()) { builder.append(", serviceErrorMessage: ").append(getServiceErrorMessage()); } if (hasServiceErrorCode()) { builder.append(", serviceErrorCode: ").append(getServiceErrorCode()); } // TODO: decide whether to include serviceErrorDetails and serverStackTrace. return builder.toString(); // E.g.: // RestLiResponseException: Response status 400, serviceErrorMessage: Illegal content type "application/xml", serviceErrorCode: 999 }
static RemoteInvocationException wrapThrowable(Throwable e) { if (e instanceof RestLiResponseException) { final RestLiResponseException restliException = (RestLiResponseException) e; final ErrorResponse errorResponse; try { errorResponse = getErrorResponse(restliException.getResponse()); } catch (RestLiDecodingException decodingException) { return new RemoteInvocationException(decodingException); } return new RestLiResponseException(restliException.getResponse(), restliException.getDecodedResponse(), errorResponse, restliException); } return new RemoteInvocationException(e); }
@Test public void testGetSubResourceRequests() { Tuple2Task<Response<Message>,Response<Message>> task = Task.par(associationsGet("a", "b", "x"), associationsGet("a", "b", "y")); if (expectBatching()) { runAndWaitException(task, RestLiResponseException.class); assertTrue(((RestLiResponseException)task.getError()).getServiceErrorMessage().contains("associationsSub?ids=List(x,y)")); } else { runAndWait(getTestClassName() + ".testGetSubResourceRequests", task); assertEquals(task.get()._1().getEntity().getMessage(), "b"); assertEquals(task.get()._1().getEntity().getId(), "a"); assertEquals(task.get()._2().getEntity().getMessage(), "b"); assertEquals(task.get()._2().getEntity().getId(), "a"); } }
RestLiResponseException(ErrorResponse errorResponse) { super(createErrorRestResponse(errorResponse)); _status = errorResponse.getStatus(); _errorResponse = errorResponse; _decodedResponse = null; }
@Test public void testGetSubResourceRequestsOverrides() { Tuple2Task<Response<Message>,Response<Message>> task = Task.par(associationsGet("a", "b", "x", overrides()), associationsGet("a", "b", "y", overrides())); if (expectBatchingOverrides()) { runAndWaitException(task, RestLiResponseException.class); assertTrue(((RestLiResponseException)task.getError()).getServiceErrorMessage().contains("associationsSub?ids=List(x,y)")); } else { runAndWait(getTestClassName() + ".testGetSubResourceRequestsOverrides", task); assertEquals(task.get()._1().getEntity().getMessage(), "b"); assertEquals(task.get()._1().getEntity().getId(), "a"); assertEquals(task.get()._2().getEntity().getMessage(), "b"); assertEquals(task.get()._2().getEntity().getId(), "a"); } }
@Builder(builderMethodName = "failRequestBuilder", buildMethodName = "fail") public static void failRequest(RequestAndCallback requestAndCallback, Throwable exception, HttpStatus errorStatus) { Throwable actualException; if (errorStatus != null) { RestLiResponseException restException = Mockito.mock(RestLiResponseException.class); Mockito.when(restException.getStatus()).thenReturn(errorStatus.getCode()); actualException = restException; } else if (exception != null) { actualException = exception; } else { actualException = new RuntimeException(); } requestAndCallback.callback.onError(actualException); }
/** * Extract the get response for this resource out of an auto-batched batch response. * This is pure rest.li logic, and it complements the auto-batching logic in BatchGetRequestBuilder. * @throws com.linkedin.r2.RemoteInvocationException if the server returned an error response for this resource, * or if it returned neither a result nor an error. */ public static <K, V extends RecordTemplate> Response<V> unbatchKVResponse(Request<BatchKVResponse<K, V>> request, Response<BatchKVResponse<K, V>> batchResponse, K id) throws RemoteInvocationException { final BatchKVResponse<K, V> batchEntity = batchResponse.getEntity(); final ErrorResponse errorResponse = batchEntity.getErrors().get(id); if (errorResponse != null) { throw new RestLiResponseException(errorResponse); } final V entityResult = batchEntity.getResults().get(id); if (entityResult == null) { throw new RestLiDecodingException("No result or error for base URI " + request.getBaseUriTemplate() + ", id " + id + ". Verify that the batchGet endpoint returns response keys that match batchGet request IDs.", null); } return new ResponseImpl<V>(batchResponse, entityResult); }
@Test (dependsOnMethods = "testBadGet") public void testBadDelete() throws Exception { logger.info("+++++++++++++++++++ testBadDelete START"); FlowId flowId = new FlowId().setFlowGroup(TEST_DUMMY_GROUP_NAME_1).setFlowName(TEST_DUMMY_FLOW_NAME_1); try { this.node1FlowConfigClient.getFlowConfig(flowId); Assert.fail("Get should have raised a 404 error"); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.NOT_FOUND_404); } try { this.node2FlowConfigClient.getFlowConfig(flowId); Assert.fail("Get should have raised a 404 error"); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.NOT_FOUND_404); } logger.info("+++++++++++++++++++ testBadDelete END"); }
/** * Extract the get response for this resource out of an auto-batched batch response. * This is pure rest.li logic, and it complements the auto-batching logic in BatchGetRequestBuilder. * @throws com.linkedin.r2.RemoteInvocationException if the server returned an error response for this resource, * or if it returned neither a result nor an error. */ public static <T extends RecordTemplate> Response<T> unbatchResponse(Request<BatchResponse<T>> request, Response<BatchResponse<T>> batchResponse, Object id) throws RemoteInvocationException { final BatchResponse<T> batchEntity = batchResponse.getEntity(); final ErrorResponse errorResponse = batchEntity.getErrors().get(id); if (errorResponse != null) { throw new RestLiResponseException(errorResponse); } final T entityResult = batchEntity.getResults().get(id); if (entityResult == null) { throw new RestLiDecodingException("No result or error for base URI " + request.getBaseUriTemplate() + ", id " + id + ". Verify that the batchGet endpoint returns response keys that match batchGet request IDs.", null); } return new ResponseImpl<T>(batchResponse, entityResult); } }
@Test (dependsOnMethods = "testDelete") public void testBadGet() throws Exception { logger.info("+++++++++++++++++++ testBadGet START"); FlowId flowId = new FlowId().setFlowGroup(TEST_DUMMY_GROUP_NAME_1).setFlowName(TEST_DUMMY_FLOW_NAME_1); try { this.node1FlowConfigClient.getFlowConfig(flowId); Assert.fail("Get should have raised a 404 error"); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.NOT_FOUND_404); } try { this.node2FlowConfigClient.getFlowConfig(flowId); Assert.fail("Get should have raised a 404 error"); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.NOT_FOUND_404); } logger.info("+++++++++++++++++++ testBadGet END"); }
return new RestLiResponseException(response, decodedResponse, errorResponse, e);
@Test public void testBadGet() throws Exception { FlowId flowId = new FlowId().setFlowGroup(TEST_DUMMY_GROUP_NAME).setFlowName(TEST_DUMMY_FLOW_NAME); try { this.flowConfigClient.getFlowConfig(flowId); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.NOT_FOUND_404); return; } Assert.fail("Get should have raised a 404 error"); }
@Test public void testBadDelete() throws Exception { FlowId flowId = new FlowId().setFlowGroup(TEST_DUMMY_GROUP_NAME).setFlowName(TEST_DUMMY_FLOW_NAME); try { this.flowConfigClient.getFlowConfig(flowId); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.NOT_FOUND_404); return; } Assert.fail("Get should have raised a 404 error"); }
@Test public void testBadGet() throws Exception { FlowId flowId = new FlowId().setFlowGroup(TEST_DUMMY_GROUP_NAME).setFlowName(TEST_DUMMY_FLOW_NAME); try { _client.getFlowConfig(flowId); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.S_404_NOT_FOUND.getCode()); return; } Assert.fail("Get should have raised a 404 error"); }
@Test public void testBadDelete() throws Exception { FlowId flowId = new FlowId().setFlowGroup(TEST_DUMMY_GROUP_NAME).setFlowName(TEST_DUMMY_FLOW_NAME); try { _client.getFlowConfig(flowId); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.S_404_NOT_FOUND.getCode()); return; } Assert.fail("Get should have raised a 404 error"); }
@Test (dependsOnMethods = "testUpdate") public void testDelete() throws Exception { logger.info("+++++++++++++++++++ testDelete START"); FlowId flowId = new FlowId().setFlowGroup(TEST_GROUP_NAME_1).setFlowName(TEST_FLOW_NAME_1); // make sure flow config exists FlowConfig flowConfig = this.node1FlowConfigClient.getFlowConfig(flowId); Assert.assertEquals(flowConfig.getId().getFlowGroup(), TEST_GROUP_NAME_1); Assert.assertEquals(flowConfig.getId().getFlowName(), TEST_FLOW_NAME_1); this.node1FlowConfigClient.deleteFlowConfig(flowId); // Check if deletion is reflected on both nodes try { this.node1FlowConfigClient.getFlowConfig(flowId); Assert.fail("Get should have gotten a 404 error"); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.NOT_FOUND_404); } try { this.node2FlowConfigClient.getFlowConfig(flowId); Assert.fail("Get should have gotten a 404 error"); } catch (RestLiResponseException e) { Assert.assertEquals(e.getStatus(), HttpStatus.NOT_FOUND_404); } logger.info("+++++++++++++++++++ testDelete END"); }