use of com.linkedin.restli.server.ResourceContext 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.server.ResourceContext in project rest.li by linkedin.
the class ArgumentBuilder method parseEntityStringKey.
/**
* Parses the provided string key value and returns its corresponding typed key instance. This method should only be
* used to parse keys which appear in the request body.
*
* @param stringKey Key string from the entity body
* @param routingResult {@link RoutingResult} instance for the current request
* @param version {@link ProtocolVersion} instance of the current request
* @return An instance of key's corresponding type
*/
static Object parseEntityStringKey(final String stringKey, final RoutingResult routingResult, final ProtocolVersion version) {
ResourceModel resourceModel = routingResult.getResourceMethod().getResourceModel();
ResourceContext resourceContext = routingResult.getContext();
try {
Key primaryKey = resourceModel.getPrimaryKey();
String altKeyName = resourceContext.getParameter(RestConstants.ALT_KEY_PARAM);
if (altKeyName != null) {
return ArgumentUtils.translateFromAlternativeKey(ArgumentUtils.parseAlternativeKey(stringKey, altKeyName, resourceModel, version), altKeyName, resourceModel);
} else if (ComplexResourceKey.class.equals(primaryKey.getType())) {
return ComplexResourceKey.parseString(stringKey, resourceModel.getKeyKeyClass(), resourceModel.getKeyParamsClass(), version);
} else if (CompoundKey.class.equals(primaryKey.getType())) {
return ArgumentUtils.parseCompoundKey(stringKey, resourceModel.getKeys(), version);
} else {
// The conversion of simple keys doesn't include URL decoding as the current version of Rest.li clients don't
// encode simple keys which appear in the request body for BATCH UPDATE and BATCH PATCH requests.
Key key = resourceModel.getPrimaryKey();
return ArgumentUtils.convertSimpleValue(stringKey, key.getDataSchema(), key.getType());
}
} catch (InvalidAlternativeKeyException | AlternativeKeyCoercerException | PathSegment.PathSegmentSyntaxException | IllegalArgumentException e) {
throw new RoutingException(String.format("Invalid key: '%s'", stringKey), HttpStatus.S_400_BAD_REQUEST.getCode());
}
}
use of com.linkedin.restli.server.ResourceContext in project rest.li by linkedin.
the class TestBatchUpdateResponseBuilder method testUpdateStatusInstantiation.
@Test(dataProvider = "updateStatusInstantiation")
public void testUpdateStatusInstantiation(RestLiResponseData responseData, UpdateStatus expectedResult) {
ResourceContext mockContext = getMockResourceContext(AllProtocolVersions.RESTLI_PROTOCOL_2_0_0.getProtocolVersion(), null);
ResourceMethodDescriptor mockDescriptor = getMockResourceMethodDescriptor(null);
RoutingResult routingResult = new RoutingResult(mockContext, mockDescriptor);
PartialRestResponse response = new BatchUpdateResponseBuilder(new ErrorResponseBuilder()).buildResponse(routingResult, responseData);
Assert.assertEquals(((BatchResponse) response.getEntity()).getResults().get("key"), expectedResult);
}
use of com.linkedin.restli.server.ResourceContext in project rest.li by linkedin.
the class TestBatchUpdateResponseBuilder method unsupportedNullKeyMapTest.
/* Note that we use also need to test using java.util.concurrent.ConcurrentHashMap. This is because rest.li checks
* for the presence of nulls returned from maps which are returned from resource methods. The checking for nulls
* is prone to a NullPointerException since contains(null) can throw an NPE from certain map implementations such as
* java.util.concurrent.ConcurrentHashMap. We want to make sure our check for the presence of nulls is done in a
* way that doesn't throw an NullPointerException.
*/
@Test(dataProvider = "unsupportedNullKeyMapData")
@SuppressWarnings("unchecked")
public void unsupportedNullKeyMapTest(Object results, ProtocolVersion protocolVersion, Map<String, UpdateStatus> expectedResults) {
ResourceContext mockContext = getMockResourceContext(protocolVersion, null);
ResourceMethodDescriptor mockDescriptor = getMockResourceMethodDescriptor(null);
RoutingResult routingResult = new RoutingResult(mockContext, mockDescriptor);
Map<String, String> headers = ResponseBuilderUtil.getHeaders();
BatchUpdateResponseBuilder batchUpdateResponseBuilder = new BatchUpdateResponseBuilder(new ErrorResponseBuilder());
RestLiResponseData responseData = batchUpdateResponseBuilder.buildRestLiResponseData(null, routingResult, results, headers, Collections.<HttpCookie>emptyList());
PartialRestResponse restResponse = batchUpdateResponseBuilder.buildResponse(routingResult, responseData);
BatchResponse<UpdateStatus> batchResponse = (BatchResponse<UpdateStatus>) restResponse.getEntity();
EasyMock.verify(mockContext, mockDescriptor);
ResponseBuilderUtil.validateHeaders(restResponse, headers);
Assert.assertEquals(batchResponse.getResults(), expectedResults);
}
use of com.linkedin.restli.server.ResourceContext in project rest.li by linkedin.
the class TestRestLiMethodInvocation method checkInvocation.
private void checkInvocation(Object resource, ResourceMethodDescriptor resourceMethodDescriptor, String httpMethod, ProtocolVersion version, String uri, String entityBody, MutablePathKeys pathkeys, final RequestExecutionCallback<RestResponse> callback, final boolean isDebugMode, final boolean expectRoutingException, final RestLiAttachmentReader expectedRequestAttachments, final RestLiResponseAttachments expectedResponseAttachments) throws URISyntaxException, RestLiSyntaxException {
assertNotNull(resource);
assertNotNull(resourceMethodDescriptor);
try {
EasyMock.replay(resource);
RestRequestBuilder builder = new RestRequestBuilder(new URI(uri)).setMethod(httpMethod).addHeaderValue("Accept", "application/json").setHeader(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, version.toString());
if (entityBody != null) {
builder.setEntity(entityBody.getBytes(Data.UTF_8_CHARSET));
}
RestRequest request = builder.build();
final ResourceContext resourceContext = new ResourceContextImpl(pathkeys, request, new RequestContext(), true, expectedRequestAttachments);
resourceContext.setResponseAttachments(expectedResponseAttachments);
RoutingResult routingResult = new RoutingResult(resourceContext, resourceMethodDescriptor);
FilterRequestContextInternal filterContext = new FilterRequestContextInternalImpl((ServerResourceContext) routingResult.getContext(), resourceMethodDescriptor);
final CountDownLatch latch = new CountDownLatch(1);
final CountDownLatch expectedRoutingExceptionLatch = new CountDownLatch(1);
RestLiArgumentBuilder adapter = _methodAdapterRegistry.getArgumentBuilder(resourceMethodDescriptor.getType());
RestLiRequestData requestData = adapter.extractRequestData(routingResult, request);
filterContext.setRequestData(requestData);
RestLiResponseHandler restLiResponseHandler = new RestLiResponseHandler.Builder().build();
RequestExecutionReportBuilder requestExecutionReportBuilder = null;
if (isDebugMode) {
requestExecutionReportBuilder = new RequestExecutionReportBuilder();
}
RequestExecutionCallback<RestResponse> executionCallback = new RequestExecutionCallback<RestResponse>() {
@Override
public void onError(Throwable e, RequestExecutionReport executionReport, RestLiAttachmentReader requestAttachmentReader, RestLiResponseAttachments responseAttachments) {
if (isDebugMode) {
Assert.assertNotNull(executionReport);
} else {
Assert.assertNull(executionReport);
}
if (e.getCause().getCause() instanceof RoutingException) {
expectedRoutingExceptionLatch.countDown();
}
if (callback != null) {
callback.onError(e, executionReport, null, null);
}
Assert.assertEquals(requestAttachmentReader, expectedRequestAttachments);
Assert.assertEquals(responseAttachments, expectedResponseAttachments);
latch.countDown();
}
@Override
public void onSuccess(final RestResponse result, RequestExecutionReport executionReport, RestLiResponseAttachments responseAttachments) {
if (isDebugMode) {
Assert.assertNotNull(executionReport);
} else {
Assert.assertNull(executionReport);
}
if (callback != null) {
callback.onSuccess(result, executionReport, null);
}
Assert.assertEquals(responseAttachments, expectedResponseAttachments);
latch.countDown();
}
};
FilterChainCallback filterChainCallback = new FilterChainCallbackImpl(routingResult, _invoker, adapter, requestExecutionReportBuilder, expectedRequestAttachments, restLiResponseHandler, executionCallback);
final RestLiCallback<Object> outerCallback = new RestLiCallback<Object>(filterContext, new RestLiFilterResponseContextFactory<Object>(request, routingResult, restLiResponseHandler), new RestLiFilterChain(null, filterChainCallback));
RestUtils.validateRequestHeadersAndUpdateResourceContext(request.getHeaders(), (ServerResourceContext) routingResult.getContext());
filterContext.setRequestData(adapter.extractRequestData(routingResult, request));
_invoker.invoke(filterContext.getRequestData(), routingResult, adapter, outerCallback, requestExecutionReportBuilder);
try {
latch.await();
if (expectRoutingException) {
expectedRoutingExceptionLatch.await();
}
} catch (InterruptedException e) {
// Ignore
}
EasyMock.verify(resource);
Assert.assertEquals(((ServerResourceContext) routingResult.getContext()).getResponseMimeType(), "application/json");
} catch (RestLiSyntaxException e) {
throw new RoutingException("syntax exception", 400);
} finally {
EasyMock.reset(resource);
EasyMock.makeThreadSafe(resource, true);
}
}
Aggregations