Search in sources :

Example 1 with SymbolTable

use of com.linkedin.data.codec.symbol.SymbolTable in project rest.li by linkedin.

the class RestLiSymbolTableRequestHandler method handleRequest.

@Override
public void handleRequest(RestRequest request, RequestContext requestContext, Callback<RestResponse> callback) {
    if (HttpMethod.GET != HttpMethod.valueOf(request.getMethod())) {
        LOGGER.error("GET is expected, but " + request.getMethod() + " received");
        callback.onError(RestException.forError(HttpStatus.S_405_METHOD_NOT_ALLOWED.getCode(), "Invalid method"));
        return;
    }
    // 
    // Determine response content type based on accept header.
    // Assume protobuf2 if no accept header is specified. Note that this is a deviation from the rest of rest.li
    // which assumes JSON as the default, for efficiency reasons.
    // 
    ContentType type;
    String mimeType = Optional.ofNullable(request.getHeader(RestConstants.HEADER_ACCEPT)).orElse(RestConstants.HEADER_VALUE_APPLICATION_PROTOBUF2);
    try {
        type = ContentType.getContentType(mimeType).orElseThrow(() -> new MimeTypeParseException("Invalid accept type: " + mimeType));
    } catch (MimeTypeParseException e) {
        LOGGER.error("Could not handle accept type", e);
        callback.onError(RestException.forError(HttpStatus.S_406_NOT_ACCEPTABLE.getCode(), "Invalid accept type: " + mimeType));
        return;
    }
    final String path = request.getURI().getRawPath();
    final List<UriComponent.PathSegment> pathSegments = UriComponent.decodePath(path, true);
    final SymbolTableProvider provider = SymbolTableProviderHolder.INSTANCE.getSymbolTableProvider();
    SymbolTable symbolTable = null;
    // at this point, `handleRequest` has verified that the incoming request is a symbolTable request.
    // The URL can be one of two options:
    // .../symbolTable/tableName
    // .../symbolTable
    // We check if the last path segments is "symbolTable", and if it is, we call provider.getResponseSymbolTable
    // because we do not know the table name.
    // Otherwise, we call provider.getSymbolTable
    int pathSize = pathSegments.size();
    try {
        if (pathSegments.get(pathSize - 1).getPath().equals(SYMBOL_TABLE_URI_PATH)) {
            symbolTable = provider.getResponseSymbolTable(request.getURI(), request.getHeaders());
        } else if (pathSegments.get(pathSize - 2).getPath().equals(SYMBOL_TABLE_URI_PATH)) {
            symbolTable = provider.getSymbolTable(pathSegments.get(pathSize - 1).getPath());
        } else {
            LOGGER.error("request is malformed for handling symbolTable" + request.getURI());
        }
    } catch (IllegalStateException e) {
        LOGGER.error("Exception retrieving symbol table for URI " + request.getURI());
        symbolTable = null;
    }
    if (symbolTable == null) {
        LOGGER.error("Did not find symbol table for path " + path);
        callback.onError(RestException.forError(HttpStatus.S_404_NOT_FOUND.getCode(), "Did not find symbol table"));
        return;
    }
    try {
        // Cache key is the name of the symbol table concatenated with the type used to serialize the payload.
        String cacheKey = symbolTable.getName() + ":" + type.getHeaderKey();
        ByteString serializedTable = _symbolTableNameToSerializedBytesCache.getIfPresent(cacheKey);
        if (serializedTable == null) {
            serializedTable = SymbolTableSerializer.toByteString(type.getCodec(), symbolTable);
            _symbolTableNameToSerializedBytesCache.put(cacheKey, serializedTable);
        }
        RestResponse restResponse = new RestResponseBuilder().setStatus(HttpStatus.S_200_OK.getCode()).setHeader(RestConstants.HEADER_CONTENT_TYPE, type.getHeaderKey()).setEntity(serializedTable).build();
        callback.onSuccess(restResponse);
    } catch (IOException e) {
        callback.onError(e);
    }
}
Also used : MimeTypeParseException(javax.activation.MimeTypeParseException) SymbolTableProvider(com.linkedin.data.codec.symbol.SymbolTableProvider) DefaultSymbolTableProvider(com.linkedin.data.codec.symbol.DefaultSymbolTableProvider) ContentType(com.linkedin.restli.common.ContentType) ByteString(com.linkedin.data.ByteString) RestResponse(com.linkedin.r2.message.rest.RestResponse) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) SymbolTable(com.linkedin.data.codec.symbol.SymbolTable) ByteString(com.linkedin.data.ByteString) IOException(java.io.IOException)

Example 2 with SymbolTable

use of com.linkedin.data.codec.symbol.SymbolTable in project rest.li by linkedin.

the class TestRestLiSymbolTableRequestHandler method testReturnOtherSymbolTableNonDefaultAcceptType.

@Test
public void testReturnOtherSymbolTableNonDefaultAcceptType() throws Exception {
    SymbolTable symbolTable = new InMemorySymbolTable("TestName", ImmutableList.of("Haha", "Hehe", "Hoho"));
    URI uri = URI.create("/symbolTable/OtherTable");
    RestRequest request = new RestRequestBuilder(uri).setHeader(RestConstants.HEADER_ACCEPT, ContentType.JSON.getHeaderKey()).build();
    when(_symbolTableProvider.getSymbolTable(eq("OtherTable"))).thenReturn(symbolTable);
    CompletableFuture<RestResponse> future = new CompletableFuture<>();
    _requestHandler.handleRequest(request, mock(RequestContext.class), new Callback<RestResponse>() {

        @Override
        public void onError(Throwable e) {
            future.completeExceptionally(e);
        }

        @Override
        public void onSuccess(RestResponse result) {
            future.complete(result);
        }
    });
    Assert.assertFalse(future.isCompletedExceptionally());
    Assert.assertTrue(future.isDone());
    RestResponse response = future.get();
    Assert.assertEquals(response.getStatus(), HttpStatus.S_200_OK.getCode());
    Assert.assertEquals(response.getHeader(RestConstants.HEADER_CONTENT_TYPE), ContentType.JSON.getHeaderKey());
    Assert.assertEquals(symbolTable, SymbolTableSerializer.fromByteString(response.getEntity(), ContentType.JSON.getCodec()));
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) RestRequest(com.linkedin.r2.message.rest.RestRequest) RestResponse(com.linkedin.r2.message.rest.RestResponse) InMemorySymbolTable(com.linkedin.data.codec.symbol.InMemorySymbolTable) SymbolTable(com.linkedin.data.codec.symbol.SymbolTable) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RequestContext(com.linkedin.r2.message.RequestContext) URI(java.net.URI) InMemorySymbolTable(com.linkedin.data.codec.symbol.InMemorySymbolTable) Test(org.testng.annotations.Test)

Example 3 with SymbolTable

use of com.linkedin.data.codec.symbol.SymbolTable in project rest.li by linkedin.

the class TestRestLiSymbolTableRequestHandler method testReturnOtherSymbolTable.

@Test
public void testReturnOtherSymbolTable() throws Exception {
    SymbolTable symbolTable = new InMemorySymbolTable("TestName", ImmutableList.of("Haha", "Hehe", "Hoho"));
    URI uri = URI.create("/symbolTable/OtherTable");
    RestRequest request = new RestRequestBuilder(uri).build();
    when(_symbolTableProvider.getSymbolTable(eq("OtherTable"))).thenReturn(symbolTable);
    CompletableFuture<RestResponse> future = new CompletableFuture<>();
    _requestHandler.handleRequest(request, mock(RequestContext.class), new Callback<RestResponse>() {

        @Override
        public void onError(Throwable e) {
            future.completeExceptionally(e);
        }

        @Override
        public void onSuccess(RestResponse result) {
            future.complete(result);
        }
    });
    Assert.assertFalse(future.isCompletedExceptionally());
    Assert.assertTrue(future.isDone());
    RestResponse response = future.get();
    Assert.assertEquals(response.getStatus(), HttpStatus.S_200_OK.getCode());
    Assert.assertEquals(response.getHeader(RestConstants.HEADER_CONTENT_TYPE), ContentType.PROTOBUF2.getHeaderKey());
    Assert.assertEquals(symbolTable, SymbolTableSerializer.fromByteString(response.getEntity(), ContentType.PROTOBUF2.getCodec()));
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) RestRequest(com.linkedin.r2.message.rest.RestRequest) RestResponse(com.linkedin.r2.message.rest.RestResponse) InMemorySymbolTable(com.linkedin.data.codec.symbol.InMemorySymbolTable) SymbolTable(com.linkedin.data.codec.symbol.SymbolTable) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RequestContext(com.linkedin.r2.message.RequestContext) URI(java.net.URI) InMemorySymbolTable(com.linkedin.data.codec.symbol.InMemorySymbolTable) Test(org.testng.annotations.Test)

Example 4 with SymbolTable

use of com.linkedin.data.codec.symbol.SymbolTable in project rest.li by linkedin.

the class TestRestLiSymbolTableRequestHandler method testReturnSelfSymbolTableWhenCalledWithServiceScope.

@Test
public void testReturnSelfSymbolTableWhenCalledWithServiceScope() throws Exception {
    SymbolTable symbolTable = new InMemorySymbolTable("TestName", ImmutableList.of("Haha", "Hehe", "Hoho"));
    URI uri = URI.create("/service/symbolTable");
    RestRequest request = new RestRequestBuilder(uri).build();
    when(_symbolTableProvider.getResponseSymbolTable(eq(uri), eq(Collections.emptyMap()))).thenReturn(symbolTable);
    CompletableFuture<RestResponse> future = new CompletableFuture<>();
    _requestHandler.handleRequest(request, mock(RequestContext.class), new Callback<RestResponse>() {

        @Override
        public void onError(Throwable e) {
            future.completeExceptionally(e);
        }

        @Override
        public void onSuccess(RestResponse result) {
            future.complete(result);
        }
    });
    Assert.assertFalse(future.isCompletedExceptionally());
    Assert.assertTrue(future.isDone());
    RestResponse response = future.get();
    Assert.assertEquals(response.getStatus(), HttpStatus.S_200_OK.getCode());
    Assert.assertEquals(response.getHeader(RestConstants.HEADER_CONTENT_TYPE), ContentType.PROTOBUF2.getHeaderKey());
    Assert.assertEquals(symbolTable, SymbolTableSerializer.fromByteString(response.getEntity(), ContentType.PROTOBUF2.getCodec()));
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) RestRequest(com.linkedin.r2.message.rest.RestRequest) RestResponse(com.linkedin.r2.message.rest.RestResponse) InMemorySymbolTable(com.linkedin.data.codec.symbol.InMemorySymbolTable) SymbolTable(com.linkedin.data.codec.symbol.SymbolTable) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RequestContext(com.linkedin.r2.message.RequestContext) URI(java.net.URI) InMemorySymbolTable(com.linkedin.data.codec.symbol.InMemorySymbolTable) Test(org.testng.annotations.Test)

Example 5 with SymbolTable

use of com.linkedin.data.codec.symbol.SymbolTable in project rest.li by linkedin.

the class RestLiSymbolTableProvider method getRequestSymbolTable.

@Override
public SymbolTable getRequestSymbolTable(URI requestUri) {
    // If the URI prefix doesn't match, return null.
    if (!requestUri.toString().startsWith(_uriPrefix)) {
        return null;
    }
    String serviceName = LoadBalancerUtil.getServiceNameFromUri(requestUri);
    // First check the cache.
    SymbolTable symbolTable = _serviceNameToSymbolTableCache.getIfPresent(serviceName);
    if (symbolTable != null) {
        // symbol table is used.
        return symbolTable == EmptySymbolTable.SHARED ? null : symbolTable;
    }
    try {
        URI symbolTableUri = new URI(_uriPrefix + serviceName + "/" + RestLiSymbolTableRequestHandler.SYMBOL_TABLE_URI_PATH);
        // 
        // Fetch remote symbol table, configuring the fetch to return an empty table on 404. This will ensure that
        // for services that don't have symbol tables enabled yet, we will not use any symbol tables when encoding.
        // 
        symbolTable = fetchRemoteSymbolTable(symbolTableUri, Collections.emptyMap(), true);
        if (symbolTable != null) {
            // Cache the retrieved table.
            _serviceNameToSymbolTableCache.put(serviceName, symbolTable);
            // to not use any symbol tables when encoding.
            if (symbolTable != EmptySymbolTable.SHARED) {
                _symbolTableNameToSymbolTableCache.put(_symbolTableNameHandler.extractMetadata(symbolTable.getName()).getSymbolTableName(), symbolTable);
            } else {
                return null;
            }
        }
        return symbolTable;
    } catch (URISyntaxException ex) {
        LOGGER.error("Failed to construct symbol table URI from request URI " + requestUri, ex);
    }
    return null;
}
Also used : InMemorySymbolTable(com.linkedin.data.codec.symbol.InMemorySymbolTable) SymbolTable(com.linkedin.data.codec.symbol.SymbolTable) EmptySymbolTable(com.linkedin.data.codec.symbol.EmptySymbolTable) ByteString(com.linkedin.data.ByteString) URISyntaxException(java.net.URISyntaxException) URI(java.net.URI)

Aggregations

SymbolTable (com.linkedin.data.codec.symbol.SymbolTable)13 InMemorySymbolTable (com.linkedin.data.codec.symbol.InMemorySymbolTable)12 Test (org.testng.annotations.Test)8 RestRequest (com.linkedin.r2.message.rest.RestRequest)6 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)6 URI (java.net.URI)6 ByteString (com.linkedin.data.ByteString)5 RestResponse (com.linkedin.r2.message.rest.RestResponse)5 RequestContext (com.linkedin.r2.message.RequestContext)4 CompletableFuture (java.util.concurrent.CompletableFuture)4 RestResponseBuilder (com.linkedin.r2.message.rest.RestResponseBuilder)3 EmptySymbolTable (com.linkedin.data.codec.symbol.EmptySymbolTable)2 SymbolTableProvider (com.linkedin.data.codec.symbol.SymbolTableProvider)2 URISyntaxException (java.net.URISyntaxException)2 ArrayList (java.util.ArrayList)2 HashSet (java.util.HashSet)2 DataMap (com.linkedin.data.DataMap)1 ProtobufCodecOptions (com.linkedin.data.codec.ProtobufCodecOptions)1 DefaultSymbolTableProvider (com.linkedin.data.codec.symbol.DefaultSymbolTableProvider)1 SymbolTableMetadata (com.linkedin.data.codec.symbol.SymbolTableMetadata)1