use of com.linkedin.restli.common.CollectionMetadata in project rest.li by linkedin.
the class CollectionResponseBuilder method buildRestLiResponseData.
private static RestLiResponseData buildRestLiResponseData(final RestRequest request, final RoutingResult routingResult, final List<? extends RecordTemplate> elements, final PageIncrement pageIncrement, final RecordTemplate customMetadata, final Integer totalResults, final Map<String, String> headers, final List<HttpCookie> cookies) {
//Extract the resource context that contains projection information for root object entities, metadata and paging.
final ResourceContext resourceContext = routingResult.getContext();
//Calculate paging metadata and apply projection
final CollectionMetadata paging = RestUtils.buildMetadata(request.getURI(), resourceContext, routingResult.getResourceMethod(), elements, pageIncrement, totalResults);
//PagingMetadata cannot be null at this point so we skip the null check. Notice here that we are using automatic
//intentionally since resource methods cannot explicitly project paging. However, it should be noted that client
//resource methods have the option of selectively setting the total to null. This happens if a client decides
//that they want the total in the paging response, which the resource method will see in their paging path spec,
//and then specify total when they create CollectionResult. Restli will then also subsequently separately project
//paging using this same path spec.
//Note that there is no chance of potential data loss here:
//If the client decides they don't want total in their paging response, then the resource method will
//see the lack of total in their paging path spec and then decide to set total to null. We will then also exclude it
//when we project paging.
//If the client decides they want total in their paging response, then the resource method will see total in their
//paging path spec and then decide to set total to a non null value. We will then also include it when we project
//paging.
final CollectionMetadata projectedPaging = new CollectionMetadata(RestUtils.projectFields(paging.data(), ProjectionMode.AUTOMATIC, resourceContext.getPagingProjectionMask()));
//For root object entities
List<AnyRecord> processedElements = new ArrayList<AnyRecord>(elements.size());
for (RecordTemplate entry : elements) {
//We don't permit null elements in our lists. If so, this is a developer error.
if (entry == null) {
throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Null element inside of a List returned by the resource method: " + routingResult.getResourceMethod());
}
processedElements.add(new AnyRecord(RestUtils.projectFields(entry.data(), resourceContext.getProjectionMode(), resourceContext.getProjectionMask())));
}
//Now for custom metadata
final AnyRecord projectedCustomMetadata;
if (customMetadata != null) {
projectedCustomMetadata = new AnyRecord(RestUtils.projectFields(customMetadata.data(), resourceContext.getMetadataProjectionMode(), resourceContext.getMetadataProjectionMask()));
} else {
projectedCustomMetadata = null;
}
RestLiResponseDataImpl responseData = new RestLiResponseDataImpl(HttpStatus.S_200_OK, headers, cookies);
RestLiResponseEnvelope responseEnvelope;
switch(routingResult.getResourceMethod().getType()) {
case GET_ALL:
responseEnvelope = new GetAllResponseEnvelope(processedElements, projectedPaging, projectedCustomMetadata, responseData);
break;
case FINDER:
responseEnvelope = new FinderResponseEnvelope(processedElements, projectedPaging, projectedCustomMetadata, responseData);
break;
default:
throw new IllegalStateException("Resource method is invalid for CollectionResponseBuilder");
}
responseData.setResponseEnvelope(responseEnvelope);
return responseData;
}
use of com.linkedin.restli.common.CollectionMetadata in project rest.li by linkedin.
the class TestRestLiResponseData method testCollectionResponseEnvelopeUpdates.
@Test(dataProvider = "collectionResponseEnvelopesProvider")
@SuppressWarnings("unchecked")
public void testCollectionResponseEnvelopeUpdates(RestLiResponseDataImpl responseData) {
CollectionResponseEnvelope responseEnvelope = responseData.getCollectionResponseEnvelope();
Assert.assertFalse(responseData.isErrorResponse());
Assert.assertEquals(responseEnvelope.getCollectionResponse(), Collections.<EmptyRecord>emptyList());
Assert.assertEquals(responseEnvelope.getCollectionResponsePaging(), new CollectionMetadata());
Assert.assertEquals(responseEnvelope.getCollectionResponseCustomMetadata(), new EmptyRecord());
// Swap to exception
responseData.setException(exception500);
Assert.assertNull(responseEnvelope.getCollectionResponse());
Assert.assertNull(responseEnvelope.getCollectionResponseCustomMetadata());
Assert.assertNull(responseEnvelope.getCollectionResponsePaging());
Assert.assertEquals(responseData.getServiceException(), exception500);
Assert.assertEquals(responseData.getStatus(), HttpStatus.S_500_INTERNAL_SERVER_ERROR);
// Swap back
responseEnvelope.setCollectionResponse(new ArrayList<RecordTemplate>(), new CollectionMetadata(), new EmptyRecord(), HttpStatus.S_200_OK);
Assert.assertFalse(responseData.isErrorResponse());
Assert.assertEquals(responseEnvelope.getCollectionResponse(), Collections.<EmptyRecord>emptyList());
Assert.assertEquals(responseEnvelope.getCollectionResponsePaging(), new CollectionMetadata());
Assert.assertEquals(responseEnvelope.getCollectionResponseCustomMetadata(), new EmptyRecord());
// Check mutability when available
List<EmptyRecord> temp = (List<EmptyRecord>) responseEnvelope.getCollectionResponse();
temp.add(new EmptyRecord());
Assert.assertEquals(responseEnvelope.getCollectionResponse().size(), 1);
}
use of com.linkedin.restli.common.CollectionMetadata in project rest.li by linkedin.
the class TestRestLiResponseData method testSetNullStatus.
@Test(dataProvider = "envelopeResourceMethodDataProvider")
public void testSetNullStatus(RestLiResponseData responseData, ResourceMethod resourceMethod) {
ResponseType responseType = ResponseType.fromMethodType(resourceMethod);
try {
switch(responseType) {
case SINGLE_ENTITY:
responseData.getRecordResponseEnvelope().setRecord(new EmptyRecord(), null);
Assert.fail();
break;
case BATCH_ENTITIES:
responseData.getBatchResponseEnvelope().setBatchResponseMap(Collections.<Object, BatchResponseEnvelope.BatchResponseEntry>emptyMap(), null);
Assert.fail();
break;
case CREATE_COLLECTION:
responseData.getBatchCreateResponseEnvelope().setCreateResponse(Collections.<BatchCreateResponseEnvelope.CollectionCreateResponseItem>emptyList(), null);
Assert.fail();
break;
case GET_COLLECTION:
responseData.getCollectionResponseEnvelope().setCollectionResponse(Collections.<RecordTemplate>emptyList(), new CollectionMetadata(), new EmptyRecord(), null);
break;
case STATUS_ONLY:
responseData.getEmptyResponseEnvelope().setStatus(null);
break;
default:
Assert.fail();
}
Assert.fail();
} catch (UnsupportedOperationException e) {
// expected
}
}
use of com.linkedin.restli.common.CollectionMetadata in project rest.li by linkedin.
the class TestRestLiCallback method testOnErrorWithFiltersExceptionFromFirstFilterSecondFilterHandles.
@SuppressWarnings("unchecked")
@Test(dataProvider = "provideResponseEntities")
public void testOnErrorWithFiltersExceptionFromFirstFilterSecondFilterHandles(final ResourceMethod resourceMethod, final Object entityFromFilter2) throws Exception {
// App stuff.
RestLiServiceException exFromApp = new RestLiServiceException(HttpStatus.S_404_NOT_FOUND, "App failure");
RequestExecutionReport executionReport = new RequestExecutionReportBuilder().build();
RestLiResponseAttachments responseAttachments = new RestLiResponseAttachments.Builder().build();
RestLiServiceException appException = new RestLiServiceException(HttpStatus.S_404_NOT_FOUND);
RestLiResponseDataImpl responseAppData = new RestLiResponseDataImpl(appException, Collections.<String, String>emptyMap(), Collections.<HttpCookie>emptyList());
RestLiResponseEnvelope responseAppEnvelope = EnvelopeBuilderUtil.buildBlankResponseEnvelope(resourceMethod, responseAppData);
responseAppData.setResponseEnvelope(responseAppEnvelope);
// Filter stuff.
final Exception exFromFirstFilter = new RuntimeException("Runtime exception from first filter");
RestLiServiceException filterException = new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR);
final Map<String, String> headersFromFilter = Maps.newHashMap();
headersFromFilter.put(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, AllProtocolVersions.LATEST_PROTOCOL_VERSION.toString());
String errorResponseHeaderName = HeaderUtil.getErrorResponseHeaderName(AllProtocolVersions.LATEST_PROTOCOL_VERSION);
headersFromFilter.put(errorResponseHeaderName, RestConstants.HEADER_VALUE_ERROR);
RestLiResponseDataImpl responseFilterData = new RestLiResponseDataImpl(filterException, headersFromFilter, Collections.<HttpCookie>emptyList());
RestLiResponseEnvelope responseFilterEnvelope = EnvelopeBuilderUtil.buildBlankResponseEnvelope(resourceMethod, responseFilterData);
responseFilterData.setResponseEnvelope(responseFilterEnvelope);
PartialRestResponse partialResponse = new PartialRestResponse.Builder().build();
ArgumentCaptor<RestLiServiceException> wrappedExCapture = ArgumentCaptor.forClass(RestLiServiceException.class);
RestResponse restResponse = new RestResponseBuilder().build();
final String customHeader = "Custom-Header";
final String customHeaderValue = "CustomValue";
// Setup.
when(_requestExecutionReportBuilder.build()).thenReturn(executionReport);
when(_responseHandler.buildExceptionResponseData(eq(_restRequest), eq(_routingResult), wrappedExCapture.capture(), anyMap(), anyList())).thenReturn(responseAppData);
when(_responseHandler.buildPartialResponse(_routingResult, responseAppData)).thenReturn(partialResponse);
when(_responseHandler.buildResponse(_routingResult, partialResponse)).thenReturn(restResponse);
when(_restRequest.getHeaders()).thenReturn(null);
// Mock filter behavior.
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
FilterRequestContext requestContext = (FilterRequestContext) args[1];
FilterResponseContext responseContext = (FilterResponseContext) args[2];
((RestLiResponseDataImpl) responseContext.getResponseData()).setException(exFromFirstFilter);
responseContext.getResponseData().getHeaders().putAll(headersFromFilter);
return completedFutureWithError(exFromFirstFilter);
}
}).doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
FilterRequestContext requestContext = (FilterRequestContext) args[1];
FilterResponseContext responseContext = (FilterResponseContext) args[2];
// The second filter should be invoked with details of the exception thrown by the first
// filter. Verify incoming data.
assertEquals(responseContext.getResponseData().getStatus(), HttpStatus.S_500_INTERNAL_SERVER_ERROR);
switch(ResponseType.fromMethodType(resourceMethod)) {
case SINGLE_ENTITY:
assertNull(responseContext.getResponseData().getRecordResponseEnvelope().getRecord());
break;
case GET_COLLECTION:
assertNull(responseContext.getResponseData().getCollectionResponseEnvelope().getCollectionResponse());
break;
case CREATE_COLLECTION:
assertNull(responseContext.getResponseData().getBatchCreateResponseEnvelope().getCreateResponses());
break;
case BATCH_ENTITIES:
assertNull(responseContext.getResponseData().getBatchResponseEnvelope().getBatchResponseMap());
break;
case STATUS_ONLY:
break;
}
assertEquals(responseContext.getResponseData().getHeaders(), headersFromFilter);
assertTrue(responseContext.getResponseData().isErrorResponse());
// Modify data.
responseContext.getResponseData().getHeaders().put(customHeader, customHeaderValue);
setStatus(responseContext, HttpStatus.S_402_PAYMENT_REQUIRED);
// filter.
if (entityFromFilter2 instanceof RecordTemplate) {
responseContext.getResponseData().getRecordResponseEnvelope().setRecord((RecordTemplate) entityFromFilter2, HttpStatus.S_402_PAYMENT_REQUIRED);
} else if (entityFromFilter2 instanceof List) {
responseContext.getResponseData().getCollectionResponseEnvelope().setCollectionResponse((List<? extends RecordTemplate>) entityFromFilter2, new CollectionMetadata(), null, HttpStatus.S_402_PAYMENT_REQUIRED);
} else {
Map<Object, BatchResponseEnvelope.BatchResponseEntry> responseMap = new HashMap<Object, BatchResponseEnvelope.BatchResponseEntry>();
for (Map.Entry<?, RecordTemplate> entry : ((Map<?, RecordTemplate>) entityFromFilter2).entrySet()) {
responseMap.put(entry.getKey(), new BatchResponseEnvelope.BatchResponseEntry(HttpStatus.S_200_OK, entry.getValue()));
}
responseContext.getResponseData().getBatchResponseEnvelope().setBatchResponseMap(responseMap, HttpStatus.S_402_PAYMENT_REQUIRED);
}
return CompletableFuture.completedFuture(null);
}
}).when(_filter).onError(any(Throwable.class), eq(_filterRequestContext), any(FilterResponseContext.class));
// invoke request filters so cursor is in correct place
when(_filter.onRequest(any(FilterRequestContext.class))).thenReturn(CompletableFuture.completedFuture(null));
_twoFilterChain.onRequest(_filterRequestContext, _filterResponseContextFactory);
// Invoke.
_twoFilterRestLiCallback.onError(exFromApp, executionReport, _requestAttachmentReader, responseAttachments);
// Verify.
verify(_responseHandler).buildExceptionResponseData(eq(_restRequest), eq(_routingResult), wrappedExCapture.capture(), anyMap(), anyList());
verify(_responseHandler).buildPartialResponse(_routingResult, responseAppData);
verify(_responseHandler).buildResponse(_routingResult, partialResponse);
verify(_callback).onSuccess(restResponse, executionReport, responseAttachments);
verify(_restRequest).getHeaders();
verifyZeroInteractions(_routingResult);
verifyNoMoreInteractions(_restRequest, _responseHandler, _callback);
assertNotNull(responseAppData);
assertEquals(HttpStatus.S_402_PAYMENT_REQUIRED, responseAppData.getStatus());
// Only the error header should have been cleared.
assertFalse(responseAppData.getHeaders().containsKey(errorResponseHeaderName));
assertEquals(responseAppData.getHeaders().get(customHeader), customHeaderValue);
if (entityFromFilter2 instanceof RecordTemplate) {
assertTrue(responseAppData.getResponseType() == ResponseType.SINGLE_ENTITY);
assertEquals(responseAppData.getRecordResponseEnvelope().getRecord(), entityFromFilter2);
} else if (entityFromFilter2 instanceof List) {
if (responseAppData.getResponseType() == ResponseType.GET_COLLECTION) {
assertEquals(responseAppData.getCollectionResponseEnvelope().getCollectionResponse(), entityFromFilter2);
} else {
fail();
}
} else {
assertTrue(responseAppData.getResponseType() == ResponseType.BATCH_ENTITIES);
Map<Object, RecordTemplate> values = new HashMap<Object, RecordTemplate>();
for (Map.Entry<?, BatchResponseEnvelope.BatchResponseEntry> entry : responseAppData.getBatchResponseEnvelope().getBatchResponseMap().entrySet()) {
values.put(entry.getKey(), entry.getValue().getRecord());
}
assertEquals(values, entityFromFilter2);
}
assertFalse(responseAppData.isErrorResponse());
RestLiServiceException restliEx = wrappedExCapture.getAllValues().get(0);
assertNotNull(restliEx);
assertEquals(exFromApp.getStatus(), restliEx.getStatus());
assertEquals(exFromApp.getMessage(), restliEx.getMessage());
}
use of com.linkedin.restli.common.CollectionMetadata in project rest.li by linkedin.
the class TestMockBatchCollectionResponseFactory method testCreateWithPagingAndMetadata.
@Test
public void testCreateWithPagingAndMetadata() {
List<List<Greeting>> greetingsList = new ArrayList<>();
Greeting g1 = new Greeting().setId(1L).setMessage("g1");
List<Greeting> greetings1 = Collections.singletonList(g1);
greetingsList.add(greetings1);
Greeting g2 = new Greeting().setId(2L).setMessage("g2");
List<Greeting> greetings2 = Collections.singletonList(g2);
greetingsList.add(greetings2);
List<CollectionMetadata> pagingList = new ArrayList<>();
CollectionMetadata paging1 = new CollectionMetadata().setCount(2).setStart(0).setTotal(2);
pagingList.add(paging1);
pagingList.add(null);
List<DataMap> metadataList = new ArrayList<>();
metadataList.add(null);
DataMap customMetadata2 = new DataMap();
customMetadata2.put("foo", "bar");
metadataList.add(customMetadata2);
BatchCollectionResponse<Greeting> batchCollectionResponse = MockBatchCollectionResponseFactory.create(Greeting.class, greetingsList, pagingList, metadataList);
List<BatchFinderCriteriaResult<Greeting>> elements = batchCollectionResponse.getResults();
Assert.assertEquals(elements.size(), 2);
BatchFinderCriteriaResult<Greeting> criteriaResult1 = elements.get(0);
Assert.assertEquals(criteriaResult1.getElements(), greetings1);
Assert.assertEquals(criteriaResult1.getPaging(), paging1);
Assert.assertNull(criteriaResult1.getMetadataRaw());
BatchFinderCriteriaResult<Greeting> criteriaResult2 = elements.get(1);
Assert.assertEquals(criteriaResult2.getElements(), greetings2);
Assert.assertNull(criteriaResult2.getPaging());
Assert.assertEquals(criteriaResult2.getMetadataRaw(), customMetadata2);
}
Aggregations