Search in sources :

Example 1 with MultivaluedMap

use of com.linkedin.jersey.core.util.MultivaluedMap in project rest.li by linkedin.

the class BatchGetRequestBuilderTest method testComplexKeyBatching.

@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void testComplexKeyBatching() throws URISyntaxException, PathSegmentSyntaxException {
    String expectedProtocol1Uri = "/?fields=id,message&ids%5B0%5D.$params.id=1&ids%5B0%5D.$params.message=paramMessage1&ids%5B0%5D.id=1&ids%5B0%5D.message=keyMessage1&ids%5B1%5D.$params.id=2&ids%5B1%5D.$params.message=paramMessage2&ids%5B1%5D.id=2&ids%5B1%5D.message=keyMessage2&ids%5B2%5D.$params.id=3&ids%5B2%5D.$params.message=paramMessage3&ids%5B2%5D.id=3&ids%5B2%5D.message=keyMessage3&param1=value1&param2=value2";
    ComplexResourceKey<TestRecord, TestRecord> complexKey1 = buildComplexKey(1L, "keyMessage1", 1L, "paramMessage1");
    ComplexResourceKey<TestRecord, TestRecord> complexKey2 = buildComplexKey(2L, "keyMessage2", 2L, "paramMessage2");
    ComplexResourceKey<TestRecord, TestRecord> complexKey3 = buildComplexKey(3L, "keyMessage3", 3L, "paramMessage3");
    BatchGetRequestBuilder<ComplexResourceKey<TestRecord, TestRecord>, TestRecord> batchRequestBuilder1 = new BatchGetRequestBuilder<>("/", TestRecord.class, _complexResourceSpec, RestliRequestOptions.DEFAULT_OPTIONS);
    ComplexResourceKey<TestRecord, TestRecord>[] complexKeys1 = new ComplexResourceKey[] { complexKey1, complexKey2 };
    batchRequestBuilder1.ids(complexKeys1).fields(FIELDS.id()).setParam("param2", "value2").setParam("param1", "value1");
    BatchGetRequestBuilder<ComplexResourceKey<TestRecord, TestRecord>, TestRecord> batchRequestBuilder2 = new BatchGetRequestBuilder<>("/", TestRecord.class, _complexResourceSpec, RestliRequestOptions.DEFAULT_OPTIONS);
    ComplexResourceKey<TestRecord, TestRecord>[] complexKeys2 = new ComplexResourceKey[] { complexKey2, complexKey3 };
    batchRequestBuilder2.ids(complexKeys2).fields(FIELDS.id(), FIELDS.message()).setParam("param1", "value1").setParam("param2", "value2");
    BatchGetKVRequest<ComplexResourceKey<TestRecord, TestRecord>, TestRecord> batchRequest1 = batchRequestBuilder1.buildKV();
    BatchGetKVRequest<ComplexResourceKey<TestRecord, TestRecord>, TestRecord> batchRequest2 = batchRequestBuilder2.buildKV();
    @SuppressWarnings("unchecked") BatchGetKVRequest<ComplexResourceKey<TestRecord, TestRecord>, TestRecord> batchingRequest = BatchGetRequestBuilder.batchKV(Arrays.asList(batchRequest1, batchRequest2));
    URI actualProtocol1Uri = RestliUriBuilderUtil.createUriBuilder(batchingRequest, AllProtocolVersions.RESTLI_PROTOCOL_1_0_0.getProtocolVersion()).build();
    MultivaluedMap actualParams = UriComponent.decodeQuery(actualProtocol1Uri, true);
    MultivaluedMap expectedUriParams = UriComponent.decodeQuery(URI.create(expectedProtocol1Uri), true);
    DataMap expectedParamsDataMap = null;
    DataMap actualParamsDataMap = null;
    try {
        expectedParamsDataMap = QueryParamsDataMap.parseDataMapKeys(expectedUriParams);
        actualParamsDataMap = QueryParamsDataMap.parseDataMapKeys(actualParams);
    } catch (PathSegmentSyntaxException e) {
        // Should never happen
        Assert.fail("Failed to parse data map keys!");
    }
    Assert.assertEquals(actualProtocol1Uri.getPath(), "/");
    // Apparently due to using set to compact the list of ids in
    // BatchGetRequestBuilder.batch() the order of the parameters on the url is no longer
    // reliable.
    DataList actualIds = (DataList) actualParamsDataMap.remove(RestConstants.QUERY_BATCH_IDS_PARAM);
    DataList expectedIds = (DataList) expectedParamsDataMap.remove(RestConstants.QUERY_BATCH_IDS_PARAM);
    Assert.assertEquals(new HashSet<>(actualIds), new HashSet<>(expectedIds));
    Assert.assertEquals(actualParamsDataMap, expectedParamsDataMap);
    Assert.assertEquals(batchingRequest.getBaseUriTemplate(), batchRequest1.getBaseUriTemplate());
    Assert.assertEquals(batchingRequest.getPathKeys(), batchRequest1.getPathKeys());
    Assert.assertEquals(batchingRequest.getFields(), new HashSet<>(Arrays.asList(FIELDS.id(), FIELDS.message())));
    Assert.assertEquals(batchingRequest.getObjectIds(), new HashSet<Object>(Arrays.asList(complexKey1, complexKey2, complexKey3)));
    String expectedProtocol2Uri = "/?fields=id,message&ids=List(($params:(id:1,message:paramMessage1),id:1,message:keyMessage1),($params:(id:2,message:paramMessage2),id:2,message:keyMessage2),($params:(id:3,message:paramMessage3),id:3,message:keyMessage3))&param1=value1&param2=value2";
    URI actualProtocol2Uri = RestliUriBuilderUtil.createUriBuilder(batchingRequest, AllProtocolVersions.RESTLI_PROTOCOL_2_0_0.getProtocolVersion()).build();
    Assert.assertEquals(actualProtocol2Uri.getPath(), "/");
    actualParams = UriComponent.decodeQuery(actualProtocol2Uri, true);
    MultivaluedMap expectedParams = UriComponent.decodeQuery(URI.create(expectedProtocol2Uri), true);
    // we can't compare the query param "ids" directly as ID ordering is not preserved while batching in
    // BatchGetRequestBuilder.batch()
    Assert.assertEquals(actualParams.get("ids").size(), 1);
    Assert.assertEquals(actualParams.get("ids").size(), expectedParams.get("ids").size());
    // parse out the "ids" param into a DataList and then convert it into a set
    String actualProtocol2IdsAsString = actualParams.remove("ids").get(0);
    String expectedProtocol2IdsAsString = expectedParams.remove("ids").get(0);
    DataList actualProtocol2Ids = (DataList) URIElementParser.parse(actualProtocol2IdsAsString);
    DataList expectedProtocol2Ids = (DataList) URIElementParser.parse(expectedProtocol2IdsAsString);
    Assert.assertEquals(new HashSet<>(actualProtocol2Ids.values()), new HashSet<>(expectedProtocol2Ids.values()));
    // apart from the "ids" fields everything else should be the same
    Assert.assertEquals(actualParams, expectedParams);
}
Also used : URI(java.net.URI) DataMap(com.linkedin.data.DataMap) QueryParamsDataMap(com.linkedin.restli.internal.common.QueryParamsDataMap) DataList(com.linkedin.data.DataList) PathSegmentSyntaxException(com.linkedin.restli.internal.common.PathSegment.PathSegmentSyntaxException) ComplexResourceKey(com.linkedin.restli.common.ComplexResourceKey) MultivaluedMap(com.linkedin.jersey.core.util.MultivaluedMap) TestRecord(com.linkedin.restli.client.test.TestRecord) Test(org.testng.annotations.Test)

Example 2 with MultivaluedMap

use of com.linkedin.jersey.core.util.MultivaluedMap in project rest.li by linkedin.

the class UriComponent method decodeQuery.

/**
 * Decode the query component of a URI.
 *
 * @param q the query component in encoded form.
 * @param decode true of the query parameters of the query component
 *        should be in decoded form.
 * @return the multivalued map of query parameters.
 */
public static MultivaluedMap decodeQuery(String q, boolean decode) {
    MultivaluedMap queryParameters = new MultivaluedMap();
    if (q == null || q.length() == 0) {
        return queryParameters;
    }
    int s = 0, e = 0;
    do {
        e = q.indexOf('&', s);
        if (e == -1) {
            decodeQueryParam(queryParameters, q.substring(s), decode);
        } else if (e > s) {
            decodeQueryParam(queryParameters, q.substring(s, e), decode);
        }
        s = e + 1;
    } while (s > 0 && s < q.length());
    return queryParameters;
}
Also used : MultivaluedMap(com.linkedin.jersey.core.util.MultivaluedMap)

Example 3 with MultivaluedMap

use of com.linkedin.jersey.core.util.MultivaluedMap in project rest.li by linkedin.

the class UriComponent method decodeMatrix.

/**
 * Decode the matrix component of a URI path segment.
 *
 * @param pathSegment the path segment component in encoded form.
 * @param decode true if the matrix parameters of the path segment component
 *        should be in decoded form.
 * @return the multivalued map of matrix parameters.
 */
public static MultivaluedMap decodeMatrix(String pathSegment, boolean decode) {
    MultivaluedMap matrixMap = new MultivaluedMap();
    // Skip over path segment
    int s = pathSegment.indexOf(';') + 1;
    if (s == 0 || s == pathSegment.length()) {
        return matrixMap;
    }
    int e = 0;
    do {
        e = pathSegment.indexOf(';', s);
        if (e == -1) {
            decodeMatrixParam(matrixMap, pathSegment.substring(s), decode);
        } else if (e > s) {
            decodeMatrixParam(matrixMap, pathSegment.substring(s, e), decode);
        }
        s = e + 1;
    } while (s > 0 && s < pathSegment.length());
    return matrixMap;
}
Also used : MultivaluedMap(com.linkedin.jersey.core.util.MultivaluedMap)

Example 4 with MultivaluedMap

use of com.linkedin.jersey.core.util.MultivaluedMap in project rest.li by linkedin.

the class BatchGetRequestBuilderTest method testUriGeneration.

private static void testUriGeneration(Request<?> request, String protocol1UriString, String protocol2UriString) throws URISyntaxException {
    ProtocolVersion protocol1 = AllProtocolVersions.RESTLI_PROTOCOL_1_0_0.getProtocolVersion();
    ProtocolVersion protocol2 = AllProtocolVersions.RESTLI_PROTOCOL_2_0_0.getProtocolVersion();
    URI protocol1Uri = RestliUriBuilderUtil.createUriBuilder(request, protocol1).build();
    URI protocol2Uri = RestliUriBuilderUtil.createUriBuilder(request, protocol2).build();
    // V1:
    MultivaluedMap actualQueryParamMapV1 = UriComponent.decodeQuery(protocol1Uri, true);
    MultivaluedMap expectedQueryParamMapV1 = UriComponent.decodeQuery(new URI(protocol1UriString), true);
    assertProtocolURIsMatch(actualQueryParamMapV1, expectedQueryParamMapV1, "Protocol 1");
    // V2:
    MultivaluedMap actualQueryParamMapV2 = UriComponent.decodeQuery(protocol2Uri, true);
    MultivaluedMap expectedQueryParamMapV2 = UriComponent.decodeQuery(new URI(protocol2UriString), true);
    assertProtocolURIsMatch(actualQueryParamMapV2, expectedQueryParamMapV2, "Protocol 2");
}
Also used : ProtocolVersion(com.linkedin.restli.common.ProtocolVersion) MultivaluedMap(com.linkedin.jersey.core.util.MultivaluedMap) URI(java.net.URI)

Example 5 with MultivaluedMap

use of com.linkedin.jersey.core.util.MultivaluedMap in project rest.li by linkedin.

the class DefaultDocumentationRequestHandler method processDocumentationRequest.

@SuppressWarnings("fallthrough")
private RestResponse processDocumentationRequest(Request request) {
    final String path = request.getURI().getRawPath();
    final List<UriComponent.PathSegment> pathSegments = UriComponent.decodePath(path, true);
    String prefixSegment = null;
    String actionSegment = null;
    String typeSegment = null;
    String objectSegment = null;
    switch(pathSegments.size()) {
        case 5:
            objectSegment = pathSegments.get(4).getPath();
        case 4:
            typeSegment = pathSegments.get(3).getPath();
        case 3:
            actionSegment = pathSegments.get(2).getPath();
        case 2:
            prefixSegment = pathSegments.get(1).getPath();
    }
    assert (DOC_PREFIX.equals(prefixSegment) || (HttpMethod.valueOf(request.getMethod()) == HttpMethod.OPTIONS));
    final ByteArrayOutputStream out = new ByteArrayOutputStream(BAOS_BUFFER_SIZE);
    final RenderContext renderContext = new RenderContext(out, request.getHeaders());
    final RestLiDocumentationRenderer renderer;
    if (HttpMethod.valueOf(request.getMethod()) == HttpMethod.OPTIONS) {
        renderer = _jsonRenderer;
        renderer.renderResource(prefixSegment, renderContext);
    } else if (HttpMethod.valueOf(request.getMethod()) == HttpMethod.GET) {
        if (!DOC_VIEW_DOCS_ACTION.equals(actionSegment)) {
            throw createRoutingError(path);
        }
        final MultivaluedMap queryMap = UriComponent.decodeQuery(request.getURI().getQuery(), false);
        final List<String> formatList = queryMap.get("format");
        if (formatList == null) {
            renderer = _htmlRenderer;
        } else if (formatList.size() > 1) {
            throw new RoutingException(String.format("\"format\" query parameter must be unique, where multiple are specified: %s", Arrays.toString(formatList.toArray())), HttpStatus.S_400_BAD_REQUEST.getCode());
        } else {
            renderer = (formatList.contains(DOC_JSON_FORMAT) ? _jsonRenderer : _htmlRenderer);
        }
        if (renderer == _htmlRenderer) {
            _htmlRenderer.setFormatUriProvider(docFormat -> {
                if (RestLiDocumentationRenderer.DocumentationFormat.JSON.equals(docFormat)) {
                    return UriBuilder.fromUri(_config.getServerNodeUri()).path(request.getURI().getPath()).queryParam("format", DOC_JSON_FORMAT).build();
                }
                return null;
            });
        }
        try {
            if (typeSegment == null || typeSegment.isEmpty()) {
                renderer.renderHome(renderContext);
            } else {
                if (DOC_RESOURCE_TYPE.equals(typeSegment)) {
                    if (objectSegment == null || objectSegment.isEmpty()) {
                        renderer.renderResourceHome(renderContext);
                    } else {
                        renderer.renderResource(objectSegment, renderContext);
                    }
                } else if (DOC_DATA_TYPE.equals(typeSegment)) {
                    if (objectSegment == null || objectSegment.isEmpty()) {
                        renderer.renderDataModelHome(renderContext);
                    } else {
                        renderer.renderDataModel(objectSegment, renderContext);
                    }
                } else {
                    throw createRoutingError(path);
                }
            }
        } catch (RuntimeException e) {
            if (!renderer.handleException(e, renderContext)) {
                throw e;
            }
        }
    } else {
        throw new RoutingException(HttpStatus.S_405_METHOD_NOT_ALLOWED.getCode());
    }
    return new RestResponseBuilder().setStatus(HttpStatus.S_200_OK.getCode()).setHeader(RestConstants.HEADER_CONTENT_TYPE, renderer.getMIMEType()).setEntity(out.toByteArray()).build();
}
Also used : RestRequest(com.linkedin.r2.message.rest.RestRequest) Arrays(java.util.Arrays) ClasspathResourceDataSchemaResolver(com.linkedin.data.schema.resolver.ClasspathResourceDataSchemaResolver) UriBuilder(com.linkedin.jersey.api.uri.UriBuilder) ByteArrayOutputStream(java.io.ByteArrayOutputStream) RoutingException(com.linkedin.restli.server.RoutingException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Callback(com.linkedin.common.callback.Callback) RestLiConfig(com.linkedin.restli.server.RestLiConfig) RestLiDocumentationRequestHandler(com.linkedin.restli.server.RestLiDocumentationRequestHandler) DataSchemaResolver(com.linkedin.data.schema.DataSchemaResolver) RestResponse(com.linkedin.r2.message.rest.RestResponse) ResourceModel(com.linkedin.restli.internal.server.model.ResourceModel) List(java.util.List) Request(com.linkedin.r2.message.Request) RequestContext(com.linkedin.r2.message.RequestContext) RestConstants(com.linkedin.restli.common.RestConstants) HttpStatus(com.linkedin.restli.common.HttpStatus) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) Map(java.util.Map) UriComponent(com.linkedin.jersey.api.uri.UriComponent) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) MultivaluedMap(com.linkedin.jersey.core.util.MultivaluedMap) HttpMethod(com.linkedin.restli.common.HttpMethod) RoutingException(com.linkedin.restli.server.RoutingException) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) List(java.util.List) ByteArrayOutputStream(java.io.ByteArrayOutputStream) MultivaluedMap(com.linkedin.jersey.core.util.MultivaluedMap)

Aggregations

MultivaluedMap (com.linkedin.jersey.core.util.MultivaluedMap)5 URI (java.net.URI)2 Callback (com.linkedin.common.callback.Callback)1 DataList (com.linkedin.data.DataList)1 DataMap (com.linkedin.data.DataMap)1 DataSchemaResolver (com.linkedin.data.schema.DataSchemaResolver)1 ClasspathResourceDataSchemaResolver (com.linkedin.data.schema.resolver.ClasspathResourceDataSchemaResolver)1 UriBuilder (com.linkedin.jersey.api.uri.UriBuilder)1 UriComponent (com.linkedin.jersey.api.uri.UriComponent)1 Request (com.linkedin.r2.message.Request)1 RequestContext (com.linkedin.r2.message.RequestContext)1 RestRequest (com.linkedin.r2.message.rest.RestRequest)1 RestResponse (com.linkedin.r2.message.rest.RestResponse)1 RestResponseBuilder (com.linkedin.r2.message.rest.RestResponseBuilder)1 TestRecord (com.linkedin.restli.client.test.TestRecord)1 ComplexResourceKey (com.linkedin.restli.common.ComplexResourceKey)1 HttpMethod (com.linkedin.restli.common.HttpMethod)1 HttpStatus (com.linkedin.restli.common.HttpStatus)1 ProtocolVersion (com.linkedin.restli.common.ProtocolVersion)1 RestConstants (com.linkedin.restli.common.RestConstants)1