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);
}
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);
}
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);
}
}
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);
}
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");
}
Aggregations