Search in sources :

Example 16 with ProtocolVersion

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);
    }
}
Also used : ProtocolVersion(com.linkedin.restli.common.ProtocolVersion) URI(java.net.URI) DataMap(com.linkedin.data.DataMap) QueryParamsDataMap(com.linkedin.restli.internal.common.QueryParamsDataMap) List(java.util.List) DataMap(com.linkedin.data.DataMap) Map(java.util.Map) QueryParamsDataMap(com.linkedin.restli.internal.common.QueryParamsDataMap) HashSet(java.util.HashSet)

Example 17 with ProtocolVersion

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);
}
Also used : RoutingException(com.linkedin.restli.server.RoutingException) CompoundKey(com.linkedin.restli.common.CompoundKey) ProtocolVersion(com.linkedin.restli.common.ProtocolVersion) DataMap(com.linkedin.data.DataMap) DataList(com.linkedin.data.DataList) PathSegmentSyntaxException(com.linkedin.restli.internal.common.PathSegment.PathSegmentSyntaxException) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) ComplexResourceKey(com.linkedin.restli.common.ComplexResourceKey) TemplateRuntimeException(com.linkedin.data.template.TemplateRuntimeException) LinkedList(java.util.LinkedList) DataList(com.linkedin.data.DataList) List(java.util.List) ComplexResourceKey(com.linkedin.restli.common.ComplexResourceKey) Key(com.linkedin.restli.server.Key) CompoundKey(com.linkedin.restli.common.CompoundKey) HashSet(java.util.HashSet)

Example 18 with ProtocolVersion

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: "));
    }
}
Also used : ResourceContext(com.linkedin.restli.server.ResourceContext) ServerResourceContext(com.linkedin.restli.internal.server.ServerResourceContext) CompoundKey(com.linkedin.restli.common.CompoundKey) CreateResponse(com.linkedin.restli.server.CreateResponse) ResourceMethodDescriptor(com.linkedin.restli.internal.server.model.ResourceMethodDescriptor) ProtocolVersion(com.linkedin.restli.common.ProtocolVersion) URI(java.net.URI) RoutingResult(com.linkedin.restli.internal.server.RoutingResult) RestRequest(com.linkedin.r2.message.rest.RestRequest) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) Test(org.testng.annotations.Test)

Example 19 with ProtocolVersion

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());
}
Also used : ByteString(com.linkedin.data.ByteString) CustomString(com.linkedin.restli.server.custom.types.CustomString) ProtocolVersion(com.linkedin.restli.common.ProtocolVersion) CompoundKey(com.linkedin.restli.common.CompoundKey) DiscoveredItemKey(com.linkedin.restli.server.twitter.TwitterTestDataModels.DiscoveredItemKey) ComplexResourceKey(com.linkedin.restli.common.ComplexResourceKey) Key(com.linkedin.restli.server.Key) HashSet(java.util.HashSet) Test(org.testng.annotations.Test) AfterTest(org.testng.annotations.AfterTest) BeforeTest(org.testng.annotations.BeforeTest)

Example 20 with ProtocolVersion

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);
}
Also used : RecordTemplate(com.linkedin.data.template.RecordTemplate) ByteString(com.linkedin.data.ByteString) ProtocolVersion(com.linkedin.restli.common.ProtocolVersion) URI(java.net.URI) ResourceMethod(com.linkedin.restli.common.ResourceMethod)

Aggregations

ProtocolVersion (com.linkedin.restli.common.ProtocolVersion)35 DataMap (com.linkedin.data.DataMap)12 Test (org.testng.annotations.Test)8 CompoundKey (com.linkedin.restli.common.CompoundKey)7 RestLiServiceException (com.linkedin.restli.server.RestLiServiceException)7 URI (java.net.URI)7 ServerResourceContext (com.linkedin.restli.internal.server.ServerResourceContext)5 HashMap (java.util.HashMap)5 ComplexResourceKey (com.linkedin.restli.common.ComplexResourceKey)4 ResourceMethod (com.linkedin.restli.common.ResourceMethod)4 ByteString (com.linkedin.data.ByteString)3 BatchKVResponse (com.linkedin.restli.client.response.BatchKVResponse)3 ErrorResponse (com.linkedin.restli.common.ErrorResponse)3 IdResponse (com.linkedin.restli.common.IdResponse)3 AnyRecord (com.linkedin.restli.internal.server.methods.AnyRecord)3 HttpCookie (java.net.HttpCookie)3 HashSet (java.util.HashSet)3 RecordTemplate (com.linkedin.data.template.RecordTemplate)2 MaskTree (com.linkedin.data.transform.filter.request.MaskTree)2 Foo (com.linkedin.pegasus.generator.examples.Foo)2