Search in sources :

Example 1 with CollectionMetadata

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;
}
Also used : CollectionMetadata(com.linkedin.restli.common.CollectionMetadata) ResourceContext(com.linkedin.restli.server.ResourceContext) AnyRecord(com.linkedin.restli.internal.server.methods.AnyRecord) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RecordTemplate(com.linkedin.data.template.RecordTemplate) ArrayList(java.util.ArrayList)

Example 2 with CollectionMetadata

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);
}
Also used : EmptyRecord(com.linkedin.restli.common.EmptyRecord) CollectionMetadata(com.linkedin.restli.common.CollectionMetadata) RecordTemplate(com.linkedin.data.template.RecordTemplate) ArrayList(java.util.ArrayList) List(java.util.List) Test(org.testng.annotations.Test)

Example 3 with CollectionMetadata

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
    }
}
Also used : EmptyRecord(com.linkedin.restli.common.EmptyRecord) CollectionMetadata(com.linkedin.restli.common.CollectionMetadata) ResponseType(com.linkedin.restli.internal.server.ResponseType) Test(org.testng.annotations.Test)

Example 4 with CollectionMetadata

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());
}
Also used : HashMap(java.util.HashMap) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RecordTemplate(com.linkedin.data.template.RecordTemplate) List(java.util.List) ArrayList(java.util.ArrayList) Matchers.anyList(org.mockito.Matchers.anyList) FilterRequestContext(com.linkedin.restli.server.filter.FilterRequestContext) RestLiResponseAttachments(com.linkedin.restli.server.RestLiResponseAttachments) RequestExecutionReportBuilder(com.linkedin.restli.server.RequestExecutionReportBuilder) CollectionMetadata(com.linkedin.restli.common.CollectionMetadata) RestResponse(com.linkedin.r2.message.rest.RestResponse) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) RequestExecutionReport(com.linkedin.restli.server.RequestExecutionReport) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RoutingException(com.linkedin.restli.server.RoutingException) RestException(com.linkedin.r2.message.rest.RestException) Mockito.doAnswer(org.mockito.Mockito.doAnswer) Answer(org.mockito.stubbing.Answer) FilterResponseContext(com.linkedin.restli.server.filter.FilterResponseContext) InvocationOnMock(org.mockito.invocation.InvocationOnMock) Map(java.util.Map) Matchers.anyMap(org.mockito.Matchers.anyMap) HashMap(java.util.HashMap) DataMap(com.linkedin.data.DataMap) Test(org.testng.annotations.Test) BeforeTest(org.testng.annotations.BeforeTest)

Example 5 with CollectionMetadata

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);
}
Also used : Greeting(com.linkedin.restli.examples.greetings.api.Greeting) CollectionMetadata(com.linkedin.restli.common.CollectionMetadata) ArrayList(java.util.ArrayList) DataMap(com.linkedin.data.DataMap) BatchFinderCriteriaResult(com.linkedin.restli.common.BatchFinderCriteriaResult) List(java.util.List) ArrayList(java.util.ArrayList) Test(org.testng.annotations.Test)

Aggregations

CollectionMetadata (com.linkedin.restli.common.CollectionMetadata)30 Test (org.testng.annotations.Test)18 ArrayList (java.util.ArrayList)13 DataMap (com.linkedin.data.DataMap)9 CollectionResponse (com.linkedin.restli.common.CollectionResponse)8 Greeting (com.linkedin.restli.examples.greetings.api.Greeting)8 RecordTemplate (com.linkedin.data.template.RecordTemplate)7 HashMap (java.util.HashMap)7 EmptyRecord (com.linkedin.restli.common.EmptyRecord)6 LinkArray (com.linkedin.restli.common.LinkArray)6 RestLiServiceException (com.linkedin.restli.server.RestLiServiceException)6 List (java.util.List)6 DataProvider (org.testng.annotations.DataProvider)5 Link (com.linkedin.restli.common.Link)4 AnyRecord (com.linkedin.restli.internal.server.methods.AnyRecord)4 HighLevelRecordWithDefault (com.linkedin.restli.examples.defaults.api.HighLevelRecordWithDefault)3 LowLevelRecordWithDefault (com.linkedin.restli.examples.defaults.api.LowLevelRecordWithDefault)3 ResponseType (com.linkedin.restli.internal.server.ResponseType)3 URIDetails (com.linkedin.restli.internal.testutils.URIDetails)3 DataList (com.linkedin.data.DataList)2