Search in sources :

Example 56 with DataMap

use of com.linkedin.data.DataMap in project rest.li by linkedin.

the class RestLiAnnotationReader method addFinderResourceMethod.

private static void addFinderResourceMethod(final ResourceModel model, final Method method) {
    Finder finderAnno = method.getAnnotation(Finder.class);
    if (finderAnno == null) {
        return;
    }
    String queryType = finderAnno.value();
    List<Parameter<?>> queryParameters = getParameters(model, method, ResourceMethod.FINDER);
    if (queryType != null) {
        Class<? extends RecordTemplate> metadataType = null;
        final Class<?> returnClass = getLogicalReturnClass(method);
        if (CollectionResult.class.isAssignableFrom(returnClass)) {
            final List<Class<?>> typeArguments = ReflectionUtils.getTypeArguments(CollectionResult.class, returnClass.asSubclass(CollectionResult.class));
            final Class<?> metadataClass;
            if (typeArguments == null || typeArguments.get(1) == null) {
                // the return type may leave metadata type as parameterized and specify in runtime
                metadataClass = ((Class<?>) ((ParameterizedType) getLogicalReturnType(method)).getActualTypeArguments()[1]);
            } else {
                metadataClass = typeArguments.get(1);
            }
            if (!metadataClass.equals(NoMetadata.class)) {
                metadataType = metadataClass.asSubclass(RecordTemplate.class);
            }
        }
        DataMap annotationsMap = ResourceModelAnnotation.getAnnotationsMap(method.getAnnotations());
        addDeprecatedAnnotation(annotationsMap, method);
        ResourceMethodDescriptor finderMethodDescriptor = ResourceMethodDescriptor.createForFinder(method, queryParameters, queryType, metadataType, getInterfaceType(method), annotationsMap);
        validateFinderMethod(finderMethodDescriptor, model);
        if (!Modifier.isPublic(method.getModifiers())) {
            throw new ResourceConfigException(String.format("Resource '%s' contains non-public finder method '%s'.", model.getName(), method.getName()));
        }
        model.addResourceMethodDescriptor(finderMethodDescriptor);
    }
}
Also used : NoMetadata(com.linkedin.restli.server.NoMetadata) Finder(com.linkedin.restli.server.annotations.Finder) DataMap(com.linkedin.data.DataMap) ParameterizedType(java.lang.reflect.ParameterizedType) CollectionResult(com.linkedin.restli.server.CollectionResult) RecordTemplate(com.linkedin.data.template.RecordTemplate) ResourceConfigException(com.linkedin.restli.server.ResourceConfigException)

Example 57 with DataMap

use of com.linkedin.data.DataMap in project rest.li by linkedin.

the class ActionArgumentBuilder method extractRequestData.

@Override
public RestLiRequestData extractRequestData(RoutingResult routingResult, RestRequest request) {
    ResourceMethodDescriptor resourceMethodDescriptor = routingResult.getResourceMethod();
    final DataMap data;
    if (request.getEntity() == null || request.getEntity().length() == 0) {
        data = new DataMap();
    } else {
        data = DataMapUtils.readMap(request);
    }
    DynamicRecordTemplate template = new DynamicRecordTemplate(data, resourceMethodDescriptor.getRequestDataSchema());
    ValidationResult result = ValidateDataAgainstSchema.validate(data, template.schema(), new ValidationOptions(RequiredMode.IGNORE, CoercionMode.NORMAL));
    if (!result.isValid()) {
        throw new RoutingException("Parameters of method '" + resourceMethodDescriptor.getActionName() + "' failed validation with error '" + result.getMessages() + "'", HttpStatus.S_400_BAD_REQUEST.getCode());
    }
    return new RestLiRequestDataImpl.Builder().entity(template).build();
}
Also used : DynamicRecordTemplate(com.linkedin.data.template.DynamicRecordTemplate) RoutingException(com.linkedin.restli.server.RoutingException) ResourceMethodDescriptor(com.linkedin.restli.internal.server.model.ResourceMethodDescriptor) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) DataMap(com.linkedin.data.DataMap)

Example 58 with DataMap

use of com.linkedin.data.DataMap 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 59 with DataMap

use of com.linkedin.data.DataMap in project rest.li by linkedin.

the class ResourceModelEncoder method createParameters.

private ParameterSchemaArray createParameters(final ResourceMethodDescriptor resourceMethodDescriptor) {
    ParameterSchemaArray parameterSchemaArray = new ParameterSchemaArray();
    for (Parameter<?> param : resourceMethodDescriptor.getParameters()) {
        //only custom parameters need to be specified in the IDL
        if (!param.isCustom()) {
            continue;
        }
        // assocKeys are listed outside the parameters list
        if (param.getParamType() == Parameter.ParamType.KEY || param.getParamType() == Parameter.ParamType.ASSOC_KEY_PARAM) {
            continue;
        }
        ParameterSchema paramSchema = new ParameterSchema();
        paramSchema.setName(param.getName());
        paramSchema.setType(buildDataSchemaType(param.getType(), param.getDataSchema()));
        final Object defaultValueData = param.getDefaultValueData();
        if (defaultValueData == null && param.isOptional()) {
            paramSchema.setOptional(true);
        } else if (defaultValueData != null) {
            paramSchema.setDefault(defaultValueData.toString());
        }
        String paramDoc = _docsProvider.getParamDoc(resourceMethodDescriptor.getMethod(), param.getName());
        if (paramDoc != null) {
            paramSchema.setDoc(paramDoc);
        }
        final DataMap customAnnotation = param.getCustomAnnotationData();
        if (!customAnnotation.isEmpty()) {
            paramSchema.setAnnotations(new CustomAnnotationContentSchemaMap(customAnnotation));
        }
        parameterSchemaArray.add(paramSchema);
    }
    return parameterSchemaArray;
}
Also used : ParameterSchema(com.linkedin.restli.restspec.ParameterSchema) ParameterSchemaArray(com.linkedin.restli.restspec.ParameterSchemaArray) CustomAnnotationContentSchemaMap(com.linkedin.restli.restspec.CustomAnnotationContentSchemaMap) DataMap(com.linkedin.data.DataMap)

Example 60 with DataMap

use of com.linkedin.data.DataMap in project rest.li by linkedin.

the class ResourceModelEncoder method loadOrBuildResourceSchema.

/**
   * Checks if a matching .restspec.json file exists in the classpath for the given {@link ResourceModel}.
   * If one is found it is loaded.  If not, one is built from the {@link ResourceModel}.
   *
   * The .restspec.json is preferred because it contains the exact idl that was generated for the resource
   * and also includees includes javadoc from the server class in the restspec.json.
   *
   * @param resourceModel provides the name and namespace of the schema to load or build
   * @return the {@link ResourceSchema} for the given {@link ResourceModel}
   */
public ResourceSchema loadOrBuildResourceSchema(final ResourceModel resourceModel) {
    StringBuilder resourceFilePath = new StringBuilder();
    if (resourceModel.getNamespace() != null) {
        resourceFilePath.append(resourceModel.getNamespace());
        resourceFilePath.append(".");
    }
    resourceFilePath.append(resourceModel.getName());
    resourceFilePath.append(RestConstants.RESOURCE_MODEL_FILENAME_EXTENSION);
    try {
        InputStream stream = this.getClass().getClassLoader().getResourceAsStream(resourceFilePath.toString());
        if (stream == null) {
            // restspec.json file not found, building one instead
            return buildResourceSchema(resourceModel);
        } else {
            DataMap resourceSchemaDataMap = codec.bytesToMap(IOUtils.toByteArray(stream));
            return new ResourceSchema(resourceSchemaDataMap);
        }
    } catch (IOException e) {
        throw new RuntimeException("Failed to read " + resourceFilePath.toString() + " from classpath.", e);
    }
}
Also used : ResourceSchema(com.linkedin.restli.restspec.ResourceSchema) InputStream(java.io.InputStream) IOException(java.io.IOException) DataMap(com.linkedin.data.DataMap)

Aggregations

DataMap (com.linkedin.data.DataMap)471 Test (org.testng.annotations.Test)238 DataList (com.linkedin.data.DataList)130 ByteString (com.linkedin.data.ByteString)110 HashMap (java.util.HashMap)56 TestUtil.dataMapFromString (com.linkedin.data.TestUtil.dataMapFromString)49 RecordDataSchema (com.linkedin.data.schema.RecordDataSchema)47 TestUtil.dataSchemaFromString (com.linkedin.data.TestUtil.dataSchemaFromString)46 DataSchema (com.linkedin.data.schema.DataSchema)45 Map (java.util.Map)45 ArrayList (java.util.ArrayList)31 MaskTree (com.linkedin.data.transform.filter.request.MaskTree)23 PathSpec (com.linkedin.data.schema.PathSpec)21 RecordTemplate (com.linkedin.data.template.RecordTemplate)21 DataProvider (org.testng.annotations.DataProvider)20 HashSet (java.util.HashSet)19 ArrayDataSchema (com.linkedin.data.schema.ArrayDataSchema)18 PatchTree (com.linkedin.data.transform.patch.request.PatchTree)18 CompoundKey (com.linkedin.restli.common.CompoundKey)18 IOException (java.io.IOException)18