Search in sources :

Example 1 with HeaderParam

use of com.linkedin.restli.server.annotations.HeaderParam in project rest.li by linkedin.

the class TestArgumentBuilder method testHeaderParamType.

@Test
public void testHeaderParamType() {
    String testParamKey = "testParam";
    String expectedTestParamValue = "testParamValue";
    ServerResourceContext mockResourceContext = EasyMock.createMock(ServerResourceContext.class);
    HeaderParam annotation = EasyMock.createMock(HeaderParam.class);
    EasyMock.expect(annotation.value()).andReturn(testParamKey);
    AnnotationSet annotationSet = EasyMock.createMock(AnnotationSet.class);
    EasyMock.expect(annotationSet.getAll()).andReturn(new Annotation[] {});
    EasyMock.expect(annotationSet.get(HeaderParam.class)).andReturn(annotation);
    Map<String, String> headers = new HashMap<>();
    headers.put(testParamKey, expectedTestParamValue);
    EasyMock.expect(mockResourceContext.getRequestHeaders()).andReturn(headers);
    EasyMock.expect(mockResourceContext.getRequestAttachmentReader()).andReturn(null);
    EasyMock.replay(mockResourceContext, annotation, annotationSet);
    Parameter<String> param = new Parameter<>(testParamKey, String.class, DataSchemaConstants.STRING_DATA_SCHEMA, false, null, Parameter.ParamType.HEADER, false, annotationSet);
    List<Parameter<?>> parameters = Collections.singletonList(param);
    Object[] results = ArgumentBuilder.buildArgs(new Object[0], getMockResourceMethod(parameters), mockResourceContext, null, getMockResourceMethodConfig(false));
    Assert.assertEquals(results[0], expectedTestParamValue);
}
Also used : HeaderParam(com.linkedin.restli.server.annotations.HeaderParam) ServerResourceContext(com.linkedin.restli.internal.server.ServerResourceContext) HashMap(java.util.HashMap) AnnotationSet(com.linkedin.restli.internal.server.model.AnnotationSet) Parameter(com.linkedin.restli.internal.server.model.Parameter) Test(org.testng.annotations.Test)

Example 2 with HeaderParam

use of com.linkedin.restli.server.annotations.HeaderParam in project rest.li by linkedin.

the class ArgumentBuilder method buildArgs.

/**
   * Build arguments for resource method invocation. Combines various types of arguments
   * into a single array.
   *
   * @param positionalArguments pass-through arguments coming from
   *          {@link RestLiArgumentBuilder}
   * @param resourceMethod the resource method
   * @param context {@link ResourceContext}
   * @param template {@link DynamicRecordTemplate}
   * @return array of method argument for method invocation.
   */
@SuppressWarnings("deprecation")
public static Object[] buildArgs(final Object[] positionalArguments, final ResourceMethodDescriptor resourceMethod, final ResourceContext context, final DynamicRecordTemplate template) {
    List<Parameter<?>> parameters = resourceMethod.getParameters();
    Object[] arguments = Arrays.copyOf(positionalArguments, parameters.size());
    fixUpComplexKeySingletonArraysInArguments(arguments);
    boolean attachmentsDesired = false;
    for (int i = positionalArguments.length; i < parameters.size(); ++i) {
        Parameter<?> param = parameters.get(i);
        try {
            if (param.getParamType() == Parameter.ParamType.KEY || param.getParamType() == Parameter.ParamType.ASSOC_KEY_PARAM) {
                Object value = context.getPathKeys().get(param.getName());
                if (value != null) {
                    arguments[i] = value;
                    continue;
                }
            } else if (param.getParamType() == Parameter.ParamType.CALLBACK) {
                continue;
            } else if (param.getParamType() == Parameter.ParamType.PARSEQ_CONTEXT_PARAM || param.getParamType() == Parameter.ParamType.PARSEQ_CONTEXT) {
                // don't know what to fill in yet
                continue;
            } else if (param.getParamType() == Parameter.ParamType.HEADER) {
                HeaderParam headerParam = param.getAnnotations().get(HeaderParam.class);
                String value = context.getRequestHeaders().get(headerParam.value());
                arguments[i] = value;
                continue;
            } else //we must evaluate based on the param type (annotation used)
            if (param.getParamType() == Parameter.ParamType.PROJECTION || param.getParamType() == Parameter.ParamType.PROJECTION_PARAM) {
                arguments[i] = context.getProjectionMask();
                continue;
            } else if (param.getParamType() == Parameter.ParamType.METADATA_PROJECTION_PARAM) {
                arguments[i] = context.getMetadataProjectionMask();
                continue;
            } else if (param.getParamType() == Parameter.ParamType.PAGING_PROJECTION_PARAM) {
                arguments[i] = context.getPagingProjectionMask();
                continue;
            } else if (param.getParamType() == Parameter.ParamType.CONTEXT || param.getParamType() == Parameter.ParamType.PAGING_CONTEXT_PARAM) {
                PagingContext ctx = RestUtils.getPagingContext(context, (PagingContext) param.getDefaultValue());
                arguments[i] = ctx;
                continue;
            } else if (param.getParamType() == Parameter.ParamType.PATH_KEYS || param.getParamType() == Parameter.ParamType.PATH_KEYS_PARAM) {
                arguments[i] = context.getPathKeys();
                continue;
            } else if (param.getParamType() == Parameter.ParamType.PATH_KEY_PARAM) {
                Object value = context.getPathKeys().get(param.getName());
                if (value != null) {
                    arguments[i] = value;
                    continue;
                }
            } else if (param.getParamType() == Parameter.ParamType.RESOURCE_CONTEXT || param.getParamType() == Parameter.ParamType.RESOURCE_CONTEXT_PARAM) {
                arguments[i] = context;
                continue;
            } else if (param.getParamType() == Parameter.ParamType.VALIDATOR_PARAM) {
                RestLiDataValidator validator = new RestLiDataValidator(resourceMethod.getResourceModel().getResourceClass().getAnnotations(), resourceMethod.getResourceModel().getValueClass(), resourceMethod.getMethodType());
                arguments[i] = validator;
                continue;
            } else if (param.getParamType() == Parameter.ParamType.RESTLI_ATTACHMENTS_PARAM) {
                arguments[i] = ((ServerResourceContext) context).getRequestAttachmentReader();
                attachmentsDesired = true;
                continue;
            } else if (param.getParamType() == Parameter.ParamType.POST) {
                // handle action parameters
                if (template != null) {
                    DataMap data = template.data();
                    if (data.containsKey(param.getName())) {
                        arguments[i] = template.getValue(param);
                        continue;
                    }
                }
            } else if (param.getParamType() == Parameter.ParamType.QUERY) {
                Object value;
                if (DataTemplate.class.isAssignableFrom(param.getType())) {
                    value = buildDataTemplateArgument(context, param);
                } else {
                    value = buildRegularArgument(context, param);
                }
                if (value != null) {
                    arguments[i] = value;
                    continue;
                }
            } else if (param.getParamType() == Parameter.ParamType.BATCH || param.getParamType() == Parameter.ParamType.RESOURCE_KEY) {
                // should not come to this routine since it should be handled by passing in positionalArguments
                throw new RoutingException("Parameter '" + param.getName() + "' should be passed in as a positional argument", HttpStatus.S_400_BAD_REQUEST.getCode());
            } else {
                // unknown param type
                throw new RoutingException("Parameter '" + param.getName() + "' has an unknown parameter type '" + param.getParamType().name() + "'", HttpStatus.S_400_BAD_REQUEST.getCode());
            }
        } catch (TemplateRuntimeException e) {
            throw new RoutingException("Parameter '" + param.getName() + "' is invalid", HttpStatus.S_400_BAD_REQUEST.getCode());
        }
        try {
            // check if it is optional parameter
            if (param.isOptional() && param.hasDefaultValue()) {
                arguments[i] = param.getDefaultValue();
            } else if (param.isOptional() && !param.getType().isPrimitive()) {
                // optional primitive parameter must have default value or provided
                arguments[i] = null;
            } else {
                throw new RoutingException("Parameter '" + param.getName() + "' is required", HttpStatus.S_400_BAD_REQUEST.getCode());
            }
        } catch (ResourceConfigException e) {
            // Parameter default value format exception should result in server error code 500.
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Parameter '" + param.getName() + "' default value is invalid", e);
        }
    }
    //that were not needed is safe, but not for request attachments.
    if (!attachmentsDesired && ((ServerResourceContext) context).getRequestAttachmentReader() != null) {
        throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Resource method endpoint invoked does not accept any request attachments.");
    }
    return arguments;
}
Also used : RoutingException(com.linkedin.restli.server.RoutingException) HeaderParam(com.linkedin.restli.server.annotations.HeaderParam) DataMap(com.linkedin.data.DataMap) QueryParamsDataMap(com.linkedin.restli.internal.common.QueryParamsDataMap) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RestLiDataValidator(com.linkedin.restli.common.validation.RestLiDataValidator) ServerResourceContext(com.linkedin.restli.internal.server.ServerResourceContext) PagingContext(com.linkedin.restli.server.PagingContext) TemplateRuntimeException(com.linkedin.data.template.TemplateRuntimeException) Parameter(com.linkedin.restli.internal.server.model.Parameter) ResourceConfigException(com.linkedin.restli.server.ResourceConfigException)

Example 3 with HeaderParam

use of com.linkedin.restli.server.annotations.HeaderParam in project rest.li by linkedin.

the class TestGetArgumentBuilder method testHeaderArgument.

@Test
public void testHeaderArgument() throws IOException {
    String keyName = "myComplexKeyCollectionId";
    Object keyValue = Integer.valueOf(123);
    DataSchema keySchema = new IntegerDataSchema();
    Key key = new Key(keyName, keyValue.getClass(), keySchema);
    Map<String, String> headers = new HashMap<>();
    String headerString = "An extra string.";
    headers.put("extra", headerString);
    List<Parameter<?>> headerParams = new ArrayList<>();
    headerParams.add(getIntegerParam());
    HeaderParam annotation = createMock(HeaderParam.class);
    expect(annotation.value()).andReturn("extra");
    AnnotationSet annotationSet = createMock(AnnotationSet.class);
    expect(annotationSet.getAll()).andReturn(new Annotation[] {});
    expect(annotationSet.get(HeaderParam.class)).andReturn(annotation);
    replay(annotation, annotationSet);
    Parameter<String> headerParam = new Parameter<>("", String.class, null, false, null, Parameter.ParamType.HEADER, false, annotationSet);
    headerParams.add(headerParam);
    ResourceModel model = RestLiArgumentBuilderTestHelper.getMockResourceModel(null, key, false);
    ResourceMethodDescriptor descriptor = RestLiArgumentBuilderTestHelper.getMockResourceMethodDescriptor(model, 2, headerParams);
    ServerResourceContext context = RestLiArgumentBuilderTestHelper.getMockResourceContext(keyName, keyValue, null, headers, true);
    RoutingResult routingResult = RestLiArgumentBuilderTestHelper.getMockRoutingResult(descriptor, 3, context, 2);
    RestRequest request = RestLiArgumentBuilderTestHelper.getMockRequest(false, null);
    RestLiArgumentBuilder argumentBuilder = new GetArgumentBuilder();
    RestLiRequestData requestData = argumentBuilder.extractRequestData(routingResult, null);
    Object[] args = argumentBuilder.buildArguments(requestData, routingResult);
    Object[] expectedArgs = new Object[] { keyValue, headerString };
    assertEquals(args, expectedArgs);
    verify(model, descriptor, context, routingResult, request, annotation, annotationSet);
}
Also used : HeaderParam(com.linkedin.restli.server.annotations.HeaderParam) IntegerDataSchema(com.linkedin.data.schema.IntegerDataSchema) HashMap(java.util.HashMap) ResourceMethodDescriptor(com.linkedin.restli.internal.server.model.ResourceMethodDescriptor) ArrayList(java.util.ArrayList) AnnotationSet(com.linkedin.restli.internal.server.model.AnnotationSet) DataSchema(com.linkedin.data.schema.DataSchema) IntegerDataSchema(com.linkedin.data.schema.IntegerDataSchema) RoutingResult(com.linkedin.restli.internal.server.RoutingResult) RestRequest(com.linkedin.r2.message.rest.RestRequest) ServerResourceContext(com.linkedin.restli.internal.server.ServerResourceContext) Parameter(com.linkedin.restli.internal.server.model.Parameter) ResourceModel(com.linkedin.restli.internal.server.model.ResourceModel) MyComplexKey(com.linkedin.restli.common.test.MyComplexKey) ComplexResourceKey(com.linkedin.restli.common.ComplexResourceKey) Key(com.linkedin.restli.server.Key) CompoundKey(com.linkedin.restli.common.CompoundKey) RestLiRequestData(com.linkedin.restli.server.RestLiRequestData) Test(org.testng.annotations.Test)

Example 4 with HeaderParam

use of com.linkedin.restli.server.annotations.HeaderParam in project rest.li by linkedin.

the class ArgumentBuilder method buildArgs.

/**
 * Build arguments for resource method invocation. Combines various types of arguments
 * into a single array.
 *
 * @param positionalArguments pass-through arguments coming from
 *          {@link RestLiArgumentBuilder}
 * @param resourceMethod the resource method
 * @param context {@link ResourceContext}
 * @param template {@link DynamicRecordTemplate}
 * @return array of method argument for method invocation.
 */
@SuppressWarnings("deprecation")
static Object[] buildArgs(final Object[] positionalArguments, final ResourceMethodDescriptor resourceMethod, final ServerResourceContext context, final DynamicRecordTemplate template, final ResourceMethodConfig resourceMethodConfig) {
    List<Parameter<?>> parameters = resourceMethod.getParameters();
    Object[] arguments = Arrays.copyOf(positionalArguments, parameters.size());
    fixUpComplexKeySingletonArraysInArguments(arguments);
    boolean attachmentsDesired = false;
    for (int i = positionalArguments.length; i < parameters.size(); ++i) {
        Parameter<?> param = parameters.get(i);
        try {
            if (param.getParamType() == Parameter.ParamType.KEY || param.getParamType() == Parameter.ParamType.ASSOC_KEY_PARAM) {
                Object value = context.getPathKeys().get(param.getName());
                if (value != null) {
                    arguments[i] = value;
                    continue;
                }
            } else if (param.getParamType() == Parameter.ParamType.CALLBACK) {
                continue;
            } else if (param.getParamType() == Parameter.ParamType.PARSEQ_CONTEXT_PARAM || param.getParamType() == Parameter.ParamType.PARSEQ_CONTEXT) {
                // don't know what to fill in yet
                continue;
            } else if (param.getParamType() == Parameter.ParamType.HEADER) {
                HeaderParam headerParam = param.getAnnotations().get(HeaderParam.class);
                String value = context.getRequestHeaders().get(headerParam.value());
                arguments[i] = value;
                continue;
            } else // we must evaluate based on the param type (annotation used)
            if (param.getParamType() == Parameter.ParamType.PROJECTION || param.getParamType() == Parameter.ParamType.PROJECTION_PARAM) {
                arguments[i] = context.getProjectionMask();
                continue;
            } else if (param.getParamType() == Parameter.ParamType.METADATA_PROJECTION_PARAM) {
                arguments[i] = context.getMetadataProjectionMask();
                continue;
            } else if (param.getParamType() == Parameter.ParamType.PAGING_PROJECTION_PARAM) {
                arguments[i] = context.getPagingProjectionMask();
                continue;
            } else if (param.getParamType() == Parameter.ParamType.CONTEXT || param.getParamType() == Parameter.ParamType.PAGING_CONTEXT_PARAM) {
                PagingContext ctx = RestUtils.getPagingContext(context, (PagingContext) param.getDefaultValue());
                arguments[i] = ctx;
                continue;
            } else if (param.getParamType() == Parameter.ParamType.PATH_KEYS || param.getParamType() == Parameter.ParamType.PATH_KEYS_PARAM) {
                arguments[i] = context.getPathKeys();
                continue;
            } else if (param.getParamType() == Parameter.ParamType.PATH_KEY_PARAM) {
                Object value = context.getPathKeys().get(param.getName());
                if (value != null) {
                    arguments[i] = value;
                    continue;
                }
            } else if (param.getParamType() == Parameter.ParamType.RESOURCE_CONTEXT || param.getParamType() == Parameter.ParamType.RESOURCE_CONTEXT_PARAM) {
                arguments[i] = context;
                continue;
            } else if (param.getParamType() == Parameter.ParamType.VALIDATOR_PARAM) {
                RestLiDataValidator validator = new RestLiDataValidator(resourceMethod.getResourceModel().getResourceClass().getAnnotations(), resourceMethod.getResourceModel().getValueClass(), resourceMethod.getMethodType());
                arguments[i] = validator;
                continue;
            } else if (param.getParamType() == Parameter.ParamType.RESTLI_ATTACHMENTS_PARAM) {
                arguments[i] = context.getRequestAttachmentReader();
                attachmentsDesired = true;
                continue;
            } else if (param.getParamType() == Parameter.ParamType.UNSTRUCTURED_DATA_WRITER_PARAM) {
                // The OutputStream is passed to the resource implementation in a synchronous call. Upon return of the
                // resource method, all the bytes would haven't written to the OutputStream. The EntityStream would have
                // contained all the bytes by the time data is requested. The ownership of the OutputStream is passed to
                // the ByteArrayOutputStreamWriter, which is responsible of closing the OutputStream if necessary.
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                context.setResponseEntityStream(EntityStreams.newEntityStream(new ByteArrayOutputStreamWriter(out)));
                arguments[i] = new UnstructuredDataWriter(out, context);
                continue;
            } else if (param.getParamType() == Parameter.ParamType.UNSTRUCTURED_DATA_REACTIVE_READER_PARAM) {
                arguments[i] = new UnstructuredDataReactiveReader(context.getRequestEntityStream(), context.getRawRequest().getHeader(RestConstants.HEADER_CONTENT_TYPE));
                continue;
            } else if (param.getParamType() == Parameter.ParamType.POST) {
                // handle action parameters
                if (template != null) {
                    DataMap data = template.data();
                    if (data.containsKey(param.getName())) {
                        arguments[i] = template.getValue(param);
                        continue;
                    }
                }
            } else if (param.getParamType() == Parameter.ParamType.QUERY) {
                Object value;
                if (DataTemplate.class.isAssignableFrom(param.getType())) {
                    value = buildDataTemplateArgument(context.getStructuredParameter(param.getName()), param, resourceMethodConfig.shouldValidateQueryParams());
                } else {
                    value = buildRegularArgument(context, param, resourceMethodConfig.shouldValidateQueryParams());
                }
                if (value != null) {
                    arguments[i] = value;
                    continue;
                }
            } else if (param.getParamType() == Parameter.ParamType.BATCH || param.getParamType() == Parameter.ParamType.RESOURCE_KEY) {
                // should not come to this routine since it should be handled by passing in positionalArguments
                throw new RoutingException("Parameter '" + param.getName() + "' should be passed in as a positional argument", HttpStatus.S_400_BAD_REQUEST.getCode());
            } else {
                // unknown param type
                throw new RoutingException("Parameter '" + param.getName() + "' has an unknown parameter type '" + param.getParamType().name() + "'", HttpStatus.S_400_BAD_REQUEST.getCode());
            }
        } catch (TemplateRuntimeException e) {
            throw new RoutingException("Parameter '" + param.getName() + "' is invalid", HttpStatus.S_400_BAD_REQUEST.getCode());
        }
        try {
            // check if it is optional parameter
            if (param.isOptional() && param.hasDefaultValue()) {
                arguments[i] = param.getDefaultValue();
            } else if (param.isOptional() && !param.getType().isPrimitive()) {
                // optional primitive parameter must have default value or provided
                arguments[i] = null;
            } else {
                throw new RoutingException("Parameter '" + param.getName() + "' is required", HttpStatus.S_400_BAD_REQUEST.getCode());
            }
        } catch (ResourceConfigException e) {
            // Parameter default value format exception should result in server error code 500.
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Parameter '" + param.getName() + "' default value is invalid", e);
        }
    }
    // that were not needed is safe, but not for request attachments.
    if (!attachmentsDesired && context.getRequestAttachmentReader() != null) {
        throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Resource method endpoint invoked does not accept any request attachments.");
    }
    return arguments;
}
Also used : RoutingException(com.linkedin.restli.server.RoutingException) HeaderParam(com.linkedin.restli.server.annotations.HeaderParam) UnstructuredDataReactiveReader(com.linkedin.restli.server.UnstructuredDataReactiveReader) ByteString(com.linkedin.data.ByteString) ByteArrayOutputStream(java.io.ByteArrayOutputStream) DataMap(com.linkedin.data.DataMap) QueryParamsDataMap(com.linkedin.restli.internal.common.QueryParamsDataMap) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RestLiDataValidator(com.linkedin.restli.common.validation.RestLiDataValidator) PagingContext(com.linkedin.restli.server.PagingContext) TemplateRuntimeException(com.linkedin.data.template.TemplateRuntimeException) Parameter(com.linkedin.restli.internal.server.model.Parameter) UnstructuredDataWriter(com.linkedin.restli.server.UnstructuredDataWriter) ResourceConfigException(com.linkedin.restli.server.ResourceConfigException)

Aggregations

Parameter (com.linkedin.restli.internal.server.model.Parameter)4 HeaderParam (com.linkedin.restli.server.annotations.HeaderParam)4 ServerResourceContext (com.linkedin.restli.internal.server.ServerResourceContext)3 DataMap (com.linkedin.data.DataMap)2 TemplateRuntimeException (com.linkedin.data.template.TemplateRuntimeException)2 RestLiDataValidator (com.linkedin.restli.common.validation.RestLiDataValidator)2 QueryParamsDataMap (com.linkedin.restli.internal.common.QueryParamsDataMap)2 AnnotationSet (com.linkedin.restli.internal.server.model.AnnotationSet)2 PagingContext (com.linkedin.restli.server.PagingContext)2 ResourceConfigException (com.linkedin.restli.server.ResourceConfigException)2 RestLiServiceException (com.linkedin.restli.server.RestLiServiceException)2 RoutingException (com.linkedin.restli.server.RoutingException)2 HashMap (java.util.HashMap)2 Test (org.testng.annotations.Test)2 ByteString (com.linkedin.data.ByteString)1 DataSchema (com.linkedin.data.schema.DataSchema)1 IntegerDataSchema (com.linkedin.data.schema.IntegerDataSchema)1 RestRequest (com.linkedin.r2.message.rest.RestRequest)1 ComplexResourceKey (com.linkedin.restli.common.ComplexResourceKey)1 CompoundKey (com.linkedin.restli.common.CompoundKey)1