Search in sources :

Example 6 with RecordTemplate

use of com.linkedin.data.template.RecordTemplate in project rest.li by linkedin.

the class TestRestClientRequestBuilder method clientGeneratedRestRequest.

@SuppressWarnings({ "unchecked", "rawtypes", "deprecation" })
private <T extends Request> RestRequest clientGeneratedRestRequest(Class<T> requestClass, ResourceMethod method, DataMap entityBody, RestClient.ContentType contentType, List<RestClient.AcceptType> acceptTypes, boolean acceptContentTypePerClient) throws URISyntaxException {
    // massive setup...
    Client mockClient = EasyMock.createMock(Client.class);
    @SuppressWarnings({ "rawtypes" }) Request<?> mockRequest = EasyMock.createMock(requestClass);
    RecordTemplate mockRecordTemplate = EasyMock.createMock(RecordTemplate.class);
    @SuppressWarnings({ "rawtypes" }) RestResponseDecoder mockResponseDecoder = EasyMock.createMock(RestResponseDecoder.class);
    RestliRequestOptions requestOptions = RestliRequestOptions.DEFAULT_OPTIONS;
    if (!acceptContentTypePerClient) {
        requestOptions = new RestliRequestOptions(ProtocolVersionOption.USE_LATEST_IF_AVAILABLE, null, null, contentType, acceptTypes, false);
    }
    setCommonExpectations(mockRequest, method, mockResponseDecoder, requestOptions);
    EasyMock.expect(mockRequest.getStreamingAttachments()).andReturn(null).times(2);
    setResourceMethodExpectations(method, mockRequest, mockRecordTemplate, entityBody);
    Capture<RestRequest> restRequestCapture = new Capture<RestRequest>();
    EasyMock.expect(mockClient.getMetadata(new URI(HOST + SERVICE_NAME))).andReturn(Collections.<String, Object>emptyMap()).once();
    mockClient.restRequest(EasyMock.capture(restRequestCapture), (RequestContext) EasyMock.anyObject(), (Callback<RestResponse>) EasyMock.anyObject());
    EasyMock.expectLastCall().once();
    EasyMock.replay(mockClient, mockRequest, mockRecordTemplate);
    // do work!
    RestClient restClient;
    if (acceptContentTypePerClient) {
        // configuration per client
        restClient = new RestClient(mockClient, HOST, contentType, acceptTypes);
    } else {
        // configuration per request
        restClient = new RestClient(mockClient, HOST);
    }
    restClient.sendRequest(mockRequest);
    return restRequestCapture.getValue();
}
Also used : RestResponse(com.linkedin.r2.message.rest.RestResponse) ByteString(com.linkedin.data.ByteString) URI(java.net.URI) Capture(org.easymock.Capture) RestRequest(com.linkedin.r2.message.rest.RestRequest) RestResponseDecoder(com.linkedin.restli.internal.client.RestResponseDecoder) RecordTemplate(com.linkedin.data.template.RecordTemplate) Client(com.linkedin.r2.transport.common.Client)

Example 7 with RecordTemplate

use of com.linkedin.data.template.RecordTemplate in project rest.li by linkedin.

the class BatchCreateResponseBuilder method buildRestLiResponseData.

@Override
public RestLiResponseData buildRestLiResponseData(RestRequest request, RoutingResult routingResult, Object result, Map<String, String> headers, List<HttpCookie> cookies) {
    if (result instanceof BatchCreateKVResult) {
        BatchCreateKVResult<?, ?> list = (BatchCreateKVResult<?, ?>) result;
        if (list.getResults() == null) {
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Null List inside of a BatchCreateKVResult returned by the resource method: " + routingResult.getResourceMethod());
        }
        List<BatchCreateResponseEnvelope.CollectionCreateResponseItem> collectionCreateList = new ArrayList<BatchCreateResponseEnvelope.CollectionCreateResponseItem>(list.getResults().size());
        for (CreateKVResponse e : list.getResults()) {
            if (e == null) {
                throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Null element inside of List inside of a BatchCreateResult returned by the resource method: " + routingResult.getResourceMethod());
            } else {
                Object id = ResponseUtils.translateCanonicalKeyToAlternativeKeyIfNeeded(e.getId(), routingResult);
                if (e.getError() == null) {
                    final ResourceContext resourceContext = routingResult.getContext();
                    DataMap entityData = e.getEntity() != null ? e.getEntity().data() : null;
                    final DataMap data = RestUtils.projectFields(entityData, resourceContext.getProjectionMode(), resourceContext.getProjectionMask());
                    CreateIdEntityStatus<Object, RecordTemplate> entry = new CreateIdEntityStatus<Object, RecordTemplate>(e.getStatus().getCode(), id, new AnyRecord(data), null, ProtocolVersionUtil.extractProtocolVersion(headers));
                    collectionCreateList.add(new BatchCreateResponseEnvelope.CollectionCreateResponseItem(entry));
                } else {
                    collectionCreateList.add(new BatchCreateResponseEnvelope.CollectionCreateResponseItem(e.getError(), id));
                }
            }
        }
        RestLiResponseDataImpl responseData = new RestLiResponseDataImpl(HttpStatus.S_200_OK, headers, cookies);
        responseData.setResponseEnvelope(new BatchCreateResponseEnvelope(collectionCreateList, true, responseData));
        return responseData;
    } else {
        BatchCreateResult<?, ?> list = (BatchCreateResult<?, ?>) result;
        //Verify that a null list was not passed into the BatchCreateResult. If so, this is a developer error.
        if (list.getResults() == null) {
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Null List inside of a BatchCreateResult returned by the resource method: " + routingResult.getResourceMethod());
        }
        List<BatchCreateResponseEnvelope.CollectionCreateResponseItem> collectionCreateList = new ArrayList<BatchCreateResponseEnvelope.CollectionCreateResponseItem>(list.getResults().size());
        for (CreateResponse e : list.getResults()) {
            //Verify that a null element was not passed into the BatchCreateResult list. If so, this is a developer error.
            if (e == null) {
                throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Null element inside of List inside of a BatchCreateResult returned by the resource method: " + routingResult.getResourceMethod());
            } else {
                Object id = ResponseUtils.translateCanonicalKeyToAlternativeKeyIfNeeded(e.getId(), routingResult);
                if (e.getError() == null) {
                    CreateIdStatus<Object> entry = new CreateIdStatus<Object>(e.getStatus().getCode(), id, null, ProtocolVersionUtil.extractProtocolVersion(headers));
                    collectionCreateList.add(new BatchCreateResponseEnvelope.CollectionCreateResponseItem(entry));
                } else {
                    collectionCreateList.add(new BatchCreateResponseEnvelope.CollectionCreateResponseItem(e.getError(), id));
                }
            }
        }
        RestLiResponseDataImpl responseData = new RestLiResponseDataImpl(HttpStatus.S_200_OK, headers, cookies);
        responseData.setResponseEnvelope(new BatchCreateResponseEnvelope(collectionCreateList, responseData));
        return responseData;
    }
}
Also used : ResourceContext(com.linkedin.restli.server.ResourceContext) AnyRecord(com.linkedin.restli.internal.server.methods.AnyRecord) CreateIdEntityStatus(com.linkedin.restli.common.CreateIdEntityStatus) CreateResponse(com.linkedin.restli.server.CreateResponse) ArrayList(java.util.ArrayList) CreateIdStatus(com.linkedin.restli.common.CreateIdStatus) DataMap(com.linkedin.data.DataMap) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RecordTemplate(com.linkedin.data.template.RecordTemplate) BatchCreateResult(com.linkedin.restli.server.BatchCreateResult) BatchCreateKVResult(com.linkedin.restli.server.BatchCreateKVResult) CreateKVResponse(com.linkedin.restli.server.CreateKVResponse)

Example 8 with RecordTemplate

use of com.linkedin.data.template.RecordTemplate in project rest.li by linkedin.

the class BatchGetResponseBuilder method buildRestLiResponseData.

@Override
public RestLiResponseData buildRestLiResponseData(RestRequest request, RoutingResult routingResult, Object result, Map<String, String> headers, List<HttpCookie> cookies) {
    @SuppressWarnings({ "unchecked" }) final Map<Object, RecordTemplate> /** constrained by signature of {@link com.linkedin.restli.server.resources.CollectionResource#batchGet(java.util.Set)} */
    entities = (Map<Object, RecordTemplate>) result;
    Map<Object, HttpStatus> statuses = Collections.emptyMap();
    Map<Object, RestLiServiceException> serviceErrors = Collections.emptyMap();
    if (result instanceof BatchResult) {
        @SuppressWarnings({ "unchecked" }) final BatchResult<Object, RecordTemplate> /** constrained by signature of {@link com.linkedin.restli.server.resources.CollectionResource#batchGet(java.util.Set)} */
        batchResult = (BatchResult<Object, RecordTemplate>) result;
        statuses = batchResult.getStatuses();
        serviceErrors = batchResult.getErrors();
    }
    try {
        if (statuses.containsKey(null)) {
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Null key inside of a Map returned by the resource method: " + routingResult.getResourceMethod());
        }
    } catch (NullPointerException e) {
    // Some map implementations will throw an NPE if they do not support null keys.
    // In this case it is OK to swallow this exception and proceed.
    }
    Map<Object, BatchResponseEntry> batchResult = new HashMap<Object, BatchResponseEntry>(entities.size() + serviceErrors.size());
    for (Map.Entry<Object, RecordTemplate> entity : entities.entrySet()) {
        if (entity.getKey() == null) {
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Null key inside of a Map returned by the resource method: " + routingResult.getResourceMethod());
        }
        Object finalKey = ResponseUtils.translateCanonicalKeyToAlternativeKeyIfNeeded(entity.getKey(), routingResult);
        final DataMap projectedData = RestUtils.projectFields(entity.getValue().data(), routingResult.getContext().getProjectionMode(), routingResult.getContext().getProjectionMask());
        AnyRecord anyRecord = new AnyRecord(projectedData);
        batchResult.put(finalKey, new BatchResponseEntry(statuses.get(entity.getKey()), anyRecord));
    }
    for (Map.Entry<Object, RestLiServiceException> entity : serviceErrors.entrySet()) {
        if (entity.getKey() == null || entity.getValue() == null) {
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Null key inside of a Map returned by the resource method: " + routingResult.getResourceMethod());
        }
        Object finalKey = ResponseUtils.translateCanonicalKeyToAlternativeKeyIfNeeded(entity.getKey(), routingResult);
        batchResult.put(finalKey, new BatchResponseEntry(statuses.get(entity.getKey()), entity.getValue()));
    }
    final Map<Object, RestLiServiceException> contextErrors = ((ServerResourceContext) routingResult.getContext()).getBatchKeyErrors();
    for (Map.Entry<Object, RestLiServiceException> entry : contextErrors.entrySet()) {
        Object finalKey = ResponseUtils.translateCanonicalKeyToAlternativeKeyIfNeeded(entry.getKey(), routingResult);
        batchResult.put(finalKey, new BatchResponseEntry(statuses.get(entry.getKey()), entry.getValue()));
    }
    RestLiResponseDataImpl responseData = new RestLiResponseDataImpl(HttpStatus.S_200_OK, headers, cookies);
    responseData.setResponseEnvelope(new BatchGetResponseEnvelope(batchResult, responseData));
    return responseData;
}
Also used : AnyRecord(com.linkedin.restli.internal.server.methods.AnyRecord) HttpStatus(com.linkedin.restli.common.HttpStatus) HashMap(java.util.HashMap) BatchResult(com.linkedin.restli.server.BatchResult) DataMap(com.linkedin.data.DataMap) BatchResponseEntry(com.linkedin.restli.internal.server.response.BatchResponseEnvelope.BatchResponseEntry) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) ServerResourceContext(com.linkedin.restli.internal.server.ServerResourceContext) RecordTemplate(com.linkedin.data.template.RecordTemplate) HashMap(java.util.HashMap) DataMap(com.linkedin.data.DataMap) Map(java.util.Map)

Example 9 with RecordTemplate

use of com.linkedin.data.template.RecordTemplate 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 10 with RecordTemplate

use of com.linkedin.data.template.RecordTemplate in project rest.li by linkedin.

the class RestLiValidationFilter method onRequest.

@Override
public CompletableFuture<Void> onRequest(final FilterRequestContext requestContext) {
    Class<?> resourceClass = requestContext.getFilterResourceModel().getResourceClass();
    ResourceMethod method = requestContext.getMethodType();
    RestLiDataValidator validator = new RestLiDataValidator(resourceClass.getAnnotations(), requestContext.getFilterResourceModel().getValueClass(), method);
    RestLiRequestData requestData = requestContext.getRequestData();
    if (method == ResourceMethod.CREATE || method == ResourceMethod.UPDATE) {
        ValidationResult result = validator.validateInput(requestData.getEntity());
        if (!result.isValid()) {
            throw new RestLiServiceException(HttpStatus.S_422_UNPROCESSABLE_ENTITY, result.getMessages().toString());
        }
    } else if (method == ResourceMethod.PARTIAL_UPDATE) {
        ValidationResult result = validator.validateInput((PatchRequest) requestData.getEntity());
        if (!result.isValid()) {
            throw new RestLiServiceException(HttpStatus.S_422_UNPROCESSABLE_ENTITY, result.getMessages().toString());
        }
    } else if (method == ResourceMethod.BATCH_CREATE) {
        StringBuilder sb = new StringBuilder();
        for (RecordTemplate entity : requestData.getBatchEntities()) {
            ValidationResult result = validator.validateInput(entity);
            if (!result.isValid()) {
                sb.append(result.getMessages().toString());
            }
        }
        if (sb.length() > 0) {
            throw new RestLiServiceException(HttpStatus.S_422_UNPROCESSABLE_ENTITY, sb.toString());
        }
    } else if (method == ResourceMethod.BATCH_UPDATE || method == ResourceMethod.BATCH_PARTIAL_UPDATE) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<?, ? extends RecordTemplate> entry : requestData.getBatchKeyEntityMap().entrySet()) {
            ValidationResult result;
            if (method == ResourceMethod.BATCH_UPDATE) {
                result = validator.validateInput(entry.getValue());
            } else {
                result = validator.validateInput((PatchRequest) entry.getValue());
            }
            if (!result.isValid()) {
                sb.append("Key: ");
                sb.append(entry.getKey());
                sb.append(", ");
                sb.append(result.getMessages().toString());
            }
        }
        if (sb.length() > 0) {
            throw new RestLiServiceException(HttpStatus.S_422_UNPROCESSABLE_ENTITY, sb.toString());
        }
    }
    return CompletableFuture.completedFuture(null);
}
Also used : RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RestLiDataValidator(com.linkedin.restli.common.validation.RestLiDataValidator) RecordTemplate(com.linkedin.data.template.RecordTemplate) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) PatchRequest(com.linkedin.restli.common.PatchRequest) ResourceMethod(com.linkedin.restli.common.ResourceMethod) RestLiRequestData(com.linkedin.restli.server.RestLiRequestData)

Aggregations

RecordTemplate (com.linkedin.data.template.RecordTemplate)59 DataMap (com.linkedin.data.DataMap)23 Test (org.testng.annotations.Test)23 RestLiServiceException (com.linkedin.restli.server.RestLiServiceException)10 ComplexResourceKey (com.linkedin.restli.common.ComplexResourceKey)9 DataList (com.linkedin.data.DataList)8 DynamicRecordTemplate (com.linkedin.data.template.DynamicRecordTemplate)8 ArrayList (java.util.ArrayList)8 PathSpec (com.linkedin.data.schema.PathSpec)7 TestRecord (com.linkedin.restli.client.test.TestRecord)7 AnyRecord (com.linkedin.restli.internal.server.methods.AnyRecord)7 FilterResponseContext (com.linkedin.restli.server.filter.FilterResponseContext)7 BeforeTest (org.testng.annotations.BeforeTest)7 ByteString (com.linkedin.data.ByteString)6 RestResponseBuilder (com.linkedin.r2.message.rest.RestResponseBuilder)6 EmptyRecord (com.linkedin.restli.common.EmptyRecord)6 RequestExecutionReport (com.linkedin.restli.server.RequestExecutionReport)6 RequestExecutionReportBuilder (com.linkedin.restli.server.RequestExecutionReportBuilder)6 RestLiResponseAttachments (com.linkedin.restli.server.RestLiResponseAttachments)6 RoutingException (com.linkedin.restli.server.RoutingException)6