Search in sources :

Example 11 with ResourceContext

use of com.linkedin.restli.server.ResourceContext in project rest.li by linkedin.

the class CollectionResponseBuilder method buildRestLiResponseData.

@SuppressWarnings("unchecked")
private D buildRestLiResponseData(final Request 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);
    TimingContextUtil.beginTiming(resourceContext.getRawRequestContext(), FrameworkTimingKeys.SERVER_RESPONSE_RESTLI_PROJECTION_APPLY.key());
    // 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.
    DataMap pagingData = paging.data();
    if (resourceContext.isFillInDefaultsRequested()) {
        pagingData = (DataMap) ResponseUtils.fillInDataDefault(CollectionMetadata.dataSchema(), pagingData);
    }
    final CollectionMetadata projectedPaging = new CollectionMetadata(RestUtils.projectFields(pagingData, ProjectionMode.AUTOMATIC, resourceContext.getPagingProjectionMask()));
    // For root object entities
    List<AnyRecord> processedElements = new ArrayList<>(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());
        }
        DataMap rawData = entry.data();
        if (resourceContext.isFillInDefaultsRequested()) {
            rawData = (DataMap) ResponseUtils.fillInDataDefault(entry.schema(), rawData);
        }
        processedElements.add(new AnyRecord(RestUtils.projectFields(rawData, resourceContext)));
    }
    // Now for custom metadata
    final AnyRecord projectedCustomMetadata;
    if (customMetadata != null) {
        DataMap customMetadataWithDefault = customMetadata.data();
        if (resourceContext.isFillInDefaultsRequested()) {
            customMetadataWithDefault = (DataMap) ResponseUtils.fillInDataDefault(customMetadata.schema(), customMetadataWithDefault);
        }
        projectedCustomMetadata = new AnyRecord(RestUtils.projectFields(customMetadataWithDefault, resourceContext.getMetadataProjectionMode(), resourceContext.getMetadataProjectionMask(), resourceContext.getAlwaysProjectedFields()));
    } else {
        projectedCustomMetadata = null;
    }
    TimingContextUtil.endTiming(resourceContext.getRawRequestContext(), FrameworkTimingKeys.SERVER_RESPONSE_RESTLI_PROJECTION_APPLY.key());
    return buildResponseData(HttpStatus.S_200_OK, processedElements, projectedPaging, projectedCustomMetadata, headers, cookies);
}
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) DataMap(com.linkedin.data.DataMap)

Example 12 with ResourceContext

use of com.linkedin.restli.server.ResourceContext in project rest.li by linkedin.

the class CreateResponseBuilder method buildRestLiResponseData.

/**
 * {@inheritDoc}
 *
 * @param result The result of a Rest.li CREATE method. It is an instance of {@link CreateResponse}; or subclass
 *               {@link CreateKVResponse}, if the CREATE method returns the entity.
 */
@Override
public RestLiResponseData<CreateResponseEnvelope> buildRestLiResponseData(Request request, RoutingResult routingResult, Object result, Map<String, String> headers, List<HttpCookie> cookies) {
    CreateResponse createResponse = (CreateResponse) result;
    boolean isGetAfterCreate = createResponse instanceof CreateKVResponse;
    if (createResponse.hasError()) {
        RestLiServiceException exception = createResponse.getError();
        return new RestLiResponseDataImpl<>(new CreateResponseEnvelope(exception, isGetAfterCreate), headers, cookies);
    }
    Object id = null;
    if (createResponse.hasId()) {
        id = ResponseUtils.translateCanonicalKeyToAlternativeKeyIfNeeded(createResponse.getId(), routingResult);
        final ProtocolVersion protocolVersion = routingResult.getContext().getRestliProtocolVersion();
        String stringKey = URIParamUtils.encodeKeyForUri(id, UriComponent.Type.PATH_SEGMENT, protocolVersion);
        UriBuilder uribuilder = UriBuilder.fromUri(request.getURI());
        uribuilder.path(stringKey);
        uribuilder.replaceQuery(null);
        if (routingResult.getContext().hasParameter(RestConstants.ALT_KEY_PARAM)) {
            // add altkey param to location URI
            uribuilder.queryParam(RestConstants.ALT_KEY_PARAM, routingResult.getContext().getParameter(RestConstants.ALT_KEY_PARAM));
        }
        headers.put(RestConstants.HEADER_LOCATION, uribuilder.build((Object) null).toString());
        headers.put(HeaderUtil.getIdHeaderName(protocolVersion), URIParamUtils.encodeKeyForHeader(id, protocolVersion));
    }
    // Verify that a null status was not passed into the CreateResponse. If so, this is a developer error.
    if (createResponse.getStatus() == null) {
        throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. HttpStatus is null inside of a CreateResponse from the resource method: " + routingResult.getResourceMethod());
    }
    final ResourceContext resourceContext = routingResult.getContext();
    RecordTemplate idResponse;
    if (createResponse instanceof CreateKVResponse && resourceContext.isReturnEntityRequested()) {
        RecordTemplate entity = ((CreateKVResponse<?, ?>) createResponse).getEntity();
        // Verify that a null entity was not passed into the CreateKVResponse. If so, this is a developer error.
        if (entity == null) {
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Entity is null inside of a CreateKVResponse when the entity should be returned. In resource method: " + routingResult.getResourceMethod());
        }
        DataMap entityData = entity.data();
        TimingContextUtil.beginTiming(resourceContext.getRawRequestContext(), FrameworkTimingKeys.SERVER_RESPONSE_RESTLI_PROJECTION_APPLY.key());
        final DataMap data = RestUtils.projectFields(entityData, resourceContext);
        TimingContextUtil.endTiming(resourceContext.getRawRequestContext(), FrameworkTimingKeys.SERVER_RESPONSE_RESTLI_PROJECTION_APPLY.key());
        idResponse = new AnyRecord(data);
    // Ideally, we should set an IdEntityResponse to the envelope. But we are keeping AnyRecord
    // to make sure the runtime object is backwards compatible.
    // idResponse = new IdEntityResponse<>(id, new AnyRecord(data));
    } else // Instance of idResponse
    {
        idResponse = new IdResponse<>(id);
    }
    return new RestLiResponseDataImpl<>(new CreateResponseEnvelope(createResponse.getStatus(), idResponse, isGetAfterCreate), headers, cookies);
}
Also used : ResourceContext(com.linkedin.restli.server.ResourceContext) AnyRecord(com.linkedin.restli.internal.server.methods.AnyRecord) CreateResponse(com.linkedin.restli.server.CreateResponse) ProtocolVersion(com.linkedin.restli.common.ProtocolVersion) DataMap(com.linkedin.data.DataMap) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RecordTemplate(com.linkedin.data.template.RecordTemplate) CreateKVResponse(com.linkedin.restli.server.CreateKVResponse) UriBuilder(com.linkedin.jersey.api.uri.UriBuilder)

Example 13 with ResourceContext

use of com.linkedin.restli.server.ResourceContext in project rest.li by linkedin.

the class BatchCreateResponseBuilder method buildRestLiResponseData.

/**
 * {@inheritDoc}
 *
 * @param result The result for a Rest.li BATCH_CREATE method. It's an instance of {@link BatchCreateResult}, if the
 *               BATCH_CREATE method doesn't return the entity; or an instance of {@link BatchCreateKVResult}, if it
 *               does.
 */
@Override
public RestLiResponseData<BatchCreateResponseEnvelope> buildRestLiResponseData(Request request, RoutingResult routingResult, Object result, Map<String, String> headers, List<HttpCookie> cookies) {
    Object altKey = null;
    if (routingResult.getContext().hasParameter(RestConstants.ALT_KEY_PARAM)) {
        altKey = routingResult.getContext().getParameter(RestConstants.ALT_KEY_PARAM);
    }
    final ProtocolVersion protocolVersion = ProtocolVersionUtil.extractProtocolVersion(headers);
    final ResourceContext resourceContext = routingResult.getContext();
    if (result instanceof BatchCreateKVResult && resourceContext.isReturnEntityRequested()) {
        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<>(list.getResults().size());
        TimingContextUtil.beginTiming(routingResult.getContext().getRawRequestContext(), FrameworkTimingKeys.SERVER_RESPONSE_RESTLI_PROJECTION_APPLY.key());
        for (CreateKVResponse<?, ?> createKVResponse : list.getResults()) {
            if (createKVResponse == null) {
                throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Null element inside of List inside of a BatchCreateKVResult returned by the resource method: " + routingResult.getResourceMethod());
            } else {
                Object id = ResponseUtils.translateCanonicalKeyToAlternativeKeyIfNeeded(createKVResponse.getId(), routingResult);
                if (createKVResponse.getError() == null) {
                    DataMap entityData = createKVResponse.getEntity() != null ? createKVResponse.getEntity().data() : null;
                    final DataMap data = RestUtils.projectFields(entityData, resourceContext);
                    CreateIdEntityStatus<Object, RecordTemplate> entry = new CreateIdEntityStatus<>(createKVResponse.getStatus().getCode(), id, new AnyRecord(data), // location uri
                    getLocationUri(request, id, altKey, protocolVersion), null, protocolVersion);
                    collectionCreateList.add(new BatchCreateResponseEnvelope.CollectionCreateResponseItem(entry));
                } else {
                    collectionCreateList.add(new BatchCreateResponseEnvelope.CollectionCreateResponseItem(createKVResponse.getError()));
                }
            }
        }
        TimingContextUtil.endTiming(routingResult.getContext().getRawRequestContext(), FrameworkTimingKeys.SERVER_RESPONSE_RESTLI_PROJECTION_APPLY.key());
        return new RestLiResponseDataImpl<>(new BatchCreateResponseEnvelope(HttpStatus.S_200_OK, collectionCreateList, true), headers, cookies);
    } else {
        List<? extends CreateResponse> createResponses = extractCreateResponseList(result);
        // Verify that a null list was not passed into the BatchCreateResult. If so, this is a developer error.
        if (createResponses == 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<>(createResponses.size());
        for (CreateResponse createResponse : createResponses) {
            // Verify that a null element was not passed into the BatchCreateResult list. If so, this is a developer error.
            if (createResponse == 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(createResponse.getId(), routingResult);
                if (createResponse.getError() == null) {
                    CreateIdStatus<Object> entry = new CreateIdStatus<>(createResponse.getStatus().getCode(), id, // location uri
                    getLocationUri(request, id, altKey, protocolVersion), null, protocolVersion);
                    collectionCreateList.add(new BatchCreateResponseEnvelope.CollectionCreateResponseItem(entry));
                } else {
                    collectionCreateList.add(new BatchCreateResponseEnvelope.CollectionCreateResponseItem(createResponse.getError()));
                }
            }
        }
        return new RestLiResponseDataImpl<>(new BatchCreateResponseEnvelope(HttpStatus.S_200_OK, collectionCreateList, false), headers, cookies);
    }
}
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) ProtocolVersion(com.linkedin.restli.common.ProtocolVersion) DataMap(com.linkedin.data.DataMap) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RecordTemplate(com.linkedin.data.template.RecordTemplate) BatchCreateKVResult(com.linkedin.restli.server.BatchCreateKVResult)

Example 14 with ResourceContext

use of com.linkedin.restli.server.ResourceContext in project rest.li by linkedin.

the class PartialUpdateResponseBuilder method buildRestLiResponseData.

@Override
@SuppressWarnings({ "unchecked" })
public RestLiResponseData<PartialUpdateResponseEnvelope> buildRestLiResponseData(Request request, RoutingResult routingResult, Object result, Map<String, String> headers, List<HttpCookie> cookies) {
    UpdateResponse updateResponse = (UpdateResponse) result;
    // Verify that the status in the UpdateResponse is not null. If so, this is a developer error.
    if (updateResponse.getStatus() == null) {
        throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. HttpStatus is null inside of an UpdateResponse returned by the resource method: " + routingResult.getResourceMethod());
    }
    final ResourceContext resourceContext = routingResult.getContext();
    RecordTemplate entityResponse = null;
    // Add patched entity to the response if result is an UpdateEntityResponse and the client is asking for the entity
    if (result instanceof UpdateEntityResponse && resourceContext.isReturnEntityRequested()) {
        UpdateEntityResponse<?> updateEntityResponse = (UpdateEntityResponse<?>) updateResponse;
        if (updateEntityResponse.hasEntity()) {
            DataMap entityData = updateEntityResponse.getEntity().data();
            TimingContextUtil.beginTiming(resourceContext.getRawRequestContext(), FrameworkTimingKeys.SERVER_RESPONSE_RESTLI_PROJECTION_APPLY.key());
            final DataMap data = RestUtils.projectFields(entityData, resourceContext);
            TimingContextUtil.endTiming(resourceContext.getRawRequestContext(), FrameworkTimingKeys.SERVER_RESPONSE_RESTLI_PROJECTION_APPLY.key());
            // Returned entity is to be added to the response envelope
            entityResponse = new EntityResponse<>(data, updateEntityResponse.getEntity().getClass());
        } else {
            // If trying to return an error response, a RestLiServiceException should be thrown in the resource method.
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Unexpected null encountered. Entity is null inside of an UpdateEntityResponse returned by the resource method: " + routingResult.getResourceMethod());
        }
    }
    return new RestLiResponseDataImpl<>(new PartialUpdateResponseEnvelope(updateResponse.getStatus(), entityResponse), headers, cookies);
}
Also used : UpdateResponse(com.linkedin.restli.server.UpdateResponse) ResourceContext(com.linkedin.restli.server.ResourceContext) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RecordTemplate(com.linkedin.data.template.RecordTemplate) UpdateEntityResponse(com.linkedin.restli.server.UpdateEntityResponse) DataMap(com.linkedin.data.DataMap)

Example 15 with ResourceContext

use of com.linkedin.restli.server.ResourceContext in project rest.li by linkedin.

the class TestResourceContext method testResourceContextGetProjectionMask.

@Test(dataProvider = TestConstants.RESTLI_PROTOCOL_1_2_PREFIX + "projectionMask")
public void testResourceContextGetProjectionMask(ProtocolVersion version, String stringUri) throws Exception {
    URI uri = URI.create(stringUri);
    Map<String, String> headers = new HashMap<>(1);
    headers.put(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, version.toString());
    ResourceContext context = new ResourceContextImpl(new PathKeysImpl(), new MockRequest(uri, headers), new RequestContext());
    final MaskTree entityMask = context.getProjectionMask();
    final DataMap expectedEntityMaskMap = new DataMap();
    expectedEntityMaskMap.put("locale", 1);
    expectedEntityMaskMap.put("state", 1);
    Assert.assertEquals(entityMask.getDataMap(), expectedEntityMaskMap, "The generated DataMap for the MaskTree should be correct");
    final MaskTree metadataMask = context.getMetadataProjectionMask();
    final DataMap expectedMetadataMaskMap = new DataMap();
    expectedMetadataMaskMap.put("region", 1);
    expectedMetadataMaskMap.put("city", 1);
    Assert.assertEquals(metadataMask.getDataMap(), expectedMetadataMaskMap, "The generated DataMap for the MaskTree should be correct");
    final MaskTree pagingMask = context.getPagingProjectionMask();
    final DataMap expectedPagingMaskMap = new DataMap();
    expectedPagingMaskMap.put("start", 1);
    expectedPagingMaskMap.put("links", 1);
    Assert.assertEquals(pagingMask.getDataMap(), expectedPagingMaskMap, "The generated DataMap for the MaskTree should be correct");
}
Also used : ResourceContext(com.linkedin.restli.server.ResourceContext) ServerResourceContext(com.linkedin.restli.internal.server.ServerResourceContext) HashMap(java.util.HashMap) MaskTree(com.linkedin.data.transform.filter.request.MaskTree) PathKeysImpl(com.linkedin.restli.internal.server.PathKeysImpl) ByteString(com.linkedin.data.ByteString) RequestContext(com.linkedin.r2.message.RequestContext) URI(java.net.URI) ResourceContextImpl(com.linkedin.restli.internal.server.ResourceContextImpl) DataMap(com.linkedin.data.DataMap) Test(org.testng.annotations.Test)

Aggregations

ResourceContext (com.linkedin.restli.server.ResourceContext)25 DataMap (com.linkedin.data.DataMap)12 ServerResourceContext (com.linkedin.restli.internal.server.ServerResourceContext)11 RecordTemplate (com.linkedin.data.template.RecordTemplate)8 AnyRecord (com.linkedin.restli.internal.server.methods.AnyRecord)8 Test (org.testng.annotations.Test)8 RestLiServiceException (com.linkedin.restli.server.RestLiServiceException)7 RoutingResult (com.linkedin.restli.internal.server.RoutingResult)5 ArrayList (java.util.ArrayList)5 MaskTree (com.linkedin.data.transform.filter.request.MaskTree)4 RequestContext (com.linkedin.r2.message.RequestContext)4 PathKeysImpl (com.linkedin.restli.internal.server.PathKeysImpl)4 ResourceContextImpl (com.linkedin.restli.internal.server.ResourceContextImpl)4 ResourceMethodDescriptor (com.linkedin.restli.internal.server.model.ResourceMethodDescriptor)4 CreateResponse (com.linkedin.restli.server.CreateResponse)4 URI (java.net.URI)4 ByteString (com.linkedin.data.ByteString)3 BatchResponse (com.linkedin.restli.common.BatchResponse)3 ProtocolVersion (com.linkedin.restli.common.ProtocolVersion)3 CreateKVResponse (com.linkedin.restli.server.CreateKVResponse)3