use of com.linkedin.restli.common.ProtocolVersion in project rest.li by linkedin.
the class URIDetails method testUriGeneration.
/**
* Tests the construction and validity of the provided URI. Requires an URIDetails object with the broken down URI.
*
* @param createdURIString
* @param expectedURIDetails
*/
@SuppressWarnings({ "unchecked" })
public static void testUriGeneration(String createdURIString, URIDetails expectedURIDetails) {
final ProtocolVersion version = expectedURIDetails.getProtocolVersion();
//Compare the path. Note that in both V1 and V2 all the keys (complex, compound and simple) are serialized recursively
//in a sorted order. Hence the path will be the same regardless of the underlying Map implementation (order or unordered)
final String actualPath = createdURIString.split("\\?")[0];
Assert.assertEquals("The path should be correct", expectedURIDetails._path, actualPath);
//Move onto the rest of the URI
final URI createdURI = URI.create(createdURIString);
//We will parse the created URI into memory and compare it to what's inside the URI details
final DataMap actualURIDataMap;
//Note that the actualURIDataMap that is created is composed of query parameters (including ids) and fields
try {
if (version.compareTo(AllProtocolVersions.RESTLI_PROTOCOL_1_0_0.getProtocolVersion()) <= 0) {
//1.0 - decode and then parse into a data map
final Map<String, List<String>> queryParameters = UriComponent.decodeQuery(createdURI.getRawQuery(), true);
actualURIDataMap = QueryParamsDataMap.parseDataMapKeys(queryParameters);
} else {
//2.0 - no need to decode as the parsing decodes for us
final Map<String, List<String>> queryParameters = UriComponent.decodeQuery(createdURI.getRawQuery(), false);
actualURIDataMap = URIParamUtils.parseUriParams(queryParameters);
}
//This will cover everything except fields and ids
if (expectedURIDetails._queryParams != null) {
for (final Map.Entry<String, ?> entry : expectedURIDetails._queryParams.entrySet()) {
Assert.assertNotNull("We should have a valid (non null) key for query param: " + entry.getKey() + " in our created URI", actualURIDataMap.get(entry.getKey()));
Assert.assertEquals("The value portion of for the query param: " + entry.getKey() + " URI should be correct", actualURIDataMap.get(entry.getKey()), entry.getValue());
}
}
//IDs is to be treated a bit differently since client requests put them in a set
if (expectedURIDetails._ids != null) {
final Set<Object> idSet;
final List<Object> idList;
if (actualURIDataMap.get("ids") instanceof List) {
idList = (List<Object>) actualURIDataMap.get("ids");
} else {
//Just a single object, (i.e String, DataMap, etc...)
idList = Arrays.asList(actualURIDataMap.get("ids"));
}
idSet = new HashSet<Object>(idList);
Assert.assertEquals("The set of IDs must match", expectedURIDetails._ids, idSet);
}
//Fields is to be treated a bit differently since they could be in any order, hence we compare sets
if (expectedURIDetails._fields != null) {
final String[] fieldsArray = ((String) actualURIDataMap.get("fields")).split(",");
final Set<String> actualFieldSet = new HashSet<String>(Arrays.asList(fieldsArray));
Assert.assertEquals("The set of projection fields should be correct", expectedURIDetails._fields, actualFieldSet);
}
//Now we want to make sure that we have the desired number of keys in the actualURIDataMap
int desiredKeyCount = 0;
desiredKeyCount += expectedURIDetails._queryParams == null ? 0 : expectedURIDetails._queryParams.size();
//values stored in a single key
desiredKeyCount += expectedURIDetails._fields == null ? 0 : 1;
//values stored in a single key
desiredKeyCount += expectedURIDetails._ids == null ? 0 : 1;
Assert.assertEquals("Incorrect number of keys discovered in URI", desiredKeyCount, actualURIDataMap.size());
} catch (Exception e) {
Assert.fail("Unexpected exception when parsing created URI with exception: " + e);
}
}
use of com.linkedin.restli.common.ProtocolVersion in project rest.li by linkedin.
the class RestLiRouter method parseBatchKeysParameter.
private void parseBatchKeysParameter(final ResourceModel resource, final ServerResourceContext context) {
Class<?> keyClass = resource.getKeyClass();
ProtocolVersion version = context.getRestliProtocolVersion();
final Set<Object> batchKeys;
try {
if (context.getParameters().containsKey(RestConstants.ALT_KEY_PARAM)) {
batchKeys = parseAlternativeBatchKeys(resource, context);
} else if (ComplexResourceKey.class.equals(keyClass)) {
// Parse all query parameters into a data map.
DataMap allParametersDataMap = context.getParameters();
// Get the batch request keys from the IDS list at the root of the map.
DataList batchIds = allParametersDataMap.getDataList(RestConstants.QUERY_BATCH_IDS_PARAM);
if (batchIds == null) {
batchKeys = null;
} else if (batchIds.isEmpty()) {
batchKeys = Collections.emptySet();
} else {
batchKeys = new HashSet<Object>();
// Validate the complex keys and put them into the context batch keys
for (Object complexKey : batchIds) {
if (!(complexKey instanceof DataMap)) {
log.warn("Invalid structure of key '" + complexKey.toString() + "', skipping key.");
context.getBatchKeyErrors().put(complexKey, new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST));
continue;
}
batchKeys.add(ComplexResourceKey.buildFromDataMap((DataMap) complexKey, ComplexKeySpec.forClassesMaybeNull(resource.getKeyKeyClass(), resource.getKeyParamsClass())));
}
}
} else if (CompoundKey.class.equals(keyClass) && version.compareTo(AllProtocolVersions.RESTLI_PROTOCOL_2_0_0.getProtocolVersion()) >= 0) {
DataMap allParametersDataMap = context.getParameters();
// Get the batch request keys from the IDS list at the root of the map.
DataList batchIds = allParametersDataMap.getDataList(RestConstants.QUERY_BATCH_IDS_PARAM);
if (batchIds == null) {
batchKeys = null;
} else if (batchIds.isEmpty()) {
batchKeys = Collections.emptySet();
} else {
batchKeys = new HashSet<Object>();
// Validate the compound keys and put them into the contex batch keys
for (Object compoundKey : batchIds) {
if (!(compoundKey instanceof DataMap)) {
log.warn("Invalid structure of key '" + compoundKey.toString() + "', skipping key.");
context.getBatchKeyErrors().put(compoundKey.toString(), new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST));
continue;
}
CompoundKey finalKey;
try {
finalKey = ArgumentUtils.dataMapToCompoundKey((DataMap) compoundKey, resource.getKeys());
} catch (IllegalArgumentException e) {
log.warn("Invalid structure of key '" + compoundKey.toString() + "', skipping key.");
context.getBatchKeyErrors().put(compoundKey.toString(), new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST));
continue;
}
batchKeys.add(finalKey);
}
}
} else // collection batch get in v2, collection or association batch get in v1
if (context.hasParameter(RestConstants.QUERY_BATCH_IDS_PARAM)) {
batchKeys = new HashSet<Object>();
List<String> ids = context.getParameterValues(RestConstants.QUERY_BATCH_IDS_PARAM);
if (version.compareTo(AllProtocolVersions.RESTLI_PROTOCOL_2_0_0.getProtocolVersion()) >= 0) {
for (String id : ids) {
Key key = resource.getPrimaryKey();
Object value;
try {
// in v2, compound keys have already been converted and dealt with, so all we need to do here is convert simple values.
value = ArgumentUtils.convertSimpleValue(id, key.getDataSchema(), key.getType());
batchKeys.add(value);
} catch (NumberFormatException e) {
throw new RoutingException("NumberFormatException parsing batch key '" + id + "'", HttpStatus.S_400_BAD_REQUEST.getCode(), e);
} catch (IllegalArgumentException e) {
throw new RoutingException("IllegalArgumentException parsing batch key '" + id + "'", HttpStatus.S_400_BAD_REQUEST.getCode(), e);
}
}
} else {
for (String id : ids) {
try {
// in v1, compound keys have not been fully parsed or dealt with yet, so we need to take them into account.
Object value = parseKeyFromBatchV1(id, resource);
batchKeys.add(value);
} catch (NumberFormatException e) {
log.warn("Caught NumberFormatException parsing batch key '" + id + "', skipping key.");
context.getBatchKeyErrors().put(id, new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, null, e));
} catch (IllegalArgumentException e) {
log.warn("Caught IllegalArgumentException parsing batch key '" + id + "', skipping key.");
context.getBatchKeyErrors().put(id, new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, null, e));
} catch (PathSegmentSyntaxException e) {
log.warn("Caught IllegalArgumentException parsing batch key '" + id + "', skipping key.");
context.getBatchKeyErrors().put(id, new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, null, e));
}
}
}
} else {
batchKeys = null;
}
} catch (TemplateRuntimeException e) {
// thrown from DateTemplateUtil.coerceOutput
throw new RoutingException("Batch key parameter value is invalid", HttpStatus.S_400_BAD_REQUEST.getCode(), e);
}
context.getPathKeys().setBatchKeys(batchKeys);
}
use of com.linkedin.restli.common.ProtocolVersion in project rest.li by linkedin.
the class TestCreateResponseBuilder method testBuilderException.
@Test
public void testBuilderException() throws URISyntaxException {
CompoundKey compoundKey = new CompoundKey().append("a", "a").append("b", 1);
CreateResponse createResponse = new CreateResponse(compoundKey, null);
RestRequest restRequest = new RestRequestBuilder(new URI("/foo")).build();
ProtocolVersion protocolVersion = AllProtocolVersions.RESTLI_PROTOCOL_1_0_0.getProtocolVersion();
Map<String, String> headers = ResponseBuilderUtil.getHeaders();
headers.put(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, protocolVersion.toString());
ResourceMethodDescriptor mockDescriptor = getMockResourceMethodDescriptor(null);
ResourceContext mockContext = getMockResourceContext(protocolVersion, null);
RoutingResult routingResult = new RoutingResult(mockContext, mockDescriptor);
CreateResponseBuilder createResponseBuilder = new CreateResponseBuilder();
try {
createResponseBuilder.buildRestLiResponseData(restRequest, routingResult, createResponse, headers, Collections.<HttpCookie>emptyList());
Assert.fail("buildRestLiResponseData should have thrown an exception because the status is null!");
} catch (RestLiServiceException e) {
Assert.assertTrue(e.getMessage().contains("Unexpected null encountered. HttpStatus is null inside of a CreateResponse from the resource method: "));
}
}
use of com.linkedin.restli.common.ProtocolVersion in project rest.li by linkedin.
the class TestRestLiMethodInvocation method testHeuristicKeySyntaxDetection.
@Test
public void testHeuristicKeySyntaxDetection() throws PathSegment.PathSegmentSyntaxException {
Set<Key> keys = new HashSet<Key>(2);
keys.add(new Key("foo", Integer.class));
keys.add(new Key("bar", String.class));
// heuristic key syntax detection only occurs in Protocol Version 1.0.0
ProtocolVersion v1 = AllProtocolVersions.RESTLI_PROTOCOL_1_0_0.getProtocolVersion();
Set<String> expectedKeys = new HashSet<String>(Arrays.asList("foo", "bar"));
Assert.assertEquals(expectedKeys, ArgumentUtils.parseCompoundKey("foo:42;bar:abcd", keys, v1).getPartKeys());
Assert.assertEquals(expectedKeys, ArgumentUtils.parseCompoundKey("foo:42;bar:abcd=1&efg=2", keys, v1).getPartKeys());
Assert.assertEquals(expectedKeys, ArgumentUtils.parseCompoundKey("foo=42&bar=abcd", keys, v1).getPartKeys());
Assert.assertEquals(expectedKeys, ArgumentUtils.parseCompoundKey("foo=42&bar=abcd:1;2", keys, v1).getPartKeys());
Assert.assertEquals(expectedKeys, ArgumentUtils.parseCompoundKey("foo=42&bar=foo:42", keys, v1).getPartKeys());
Assert.assertEquals(expectedKeys, ArgumentUtils.parseCompoundKey("foo=42&bar=foo:42;bar:abcd", keys, v1).getPartKeys());
Assert.assertEquals(expectedKeys, ArgumentUtils.parseCompoundKey("foo:42;bar:foo=42&bar=abcd", keys, v1).getPartKeys());
Assert.assertEquals(expectedKeys, ArgumentUtils.parseCompoundKey("foo:42;bar:foo=42", keys, v1).getPartKeys());
}
use of com.linkedin.restli.common.ProtocolVersion in project rest.li by linkedin.
the class RestClient method sendStreamRequest.
private <T> void sendStreamRequest(final Request<T> request, RequestContext requestContext, Callback<StreamResponse> callback) {
RecordTemplate input = request.getInputRecord();
ProtocolVersion protocolVersion = getProtocolVersionForService(request);
URI requestUri = RestliUriBuilderUtil.createUriBuilder(request, _uriPrefix, protocolVersion).build();
final ResourceMethod method = request.getMethod();
final String methodName = request.getMethodName();
addDisruptContext(request.getBaseUriTemplate(), method, methodName, requestContext);
sendStreamRequestImpl(requestContext, requestUri, method, input != null ? RequestBodyTransformer.transform(request, protocolVersion) : null, request.getHeaders(), CookieUtil.encodeCookies(request.getCookies()), methodName, protocolVersion, request.getRequestOptions(), request.getStreamingAttachments(), callback);
}
Aggregations