Search in sources :

Example 11 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class RequestBuilderSpecGenerator method generateRootRequestBuilder.

private RootBuilderSpec generateRootRequestBuilder(RootBuilderSpec parentRootBuilder, ResourceSchema resource, String sourceFile, Map<String, String> pathKeyTypes) throws IOException {
    ValidationResult validationResult = ValidateDataAgainstSchema.validate(resource.data(), resource.schema(), new ValidationOptions(RequiredMode.MUST_BE_PRESENT));
    if (!validationResult.isValid()) {
        throw new IllegalArgumentException(String.format("Resource validation error.  Resource File '%s', Error Details '%s'", sourceFile, validationResult.toString()));
    }
    String packageName = resource.getNamespace();
    String resourceName = CodeUtil.capitalize(resource.getName());
    String className;
    if (_version == RestliVersion.RESTLI_2_0_0) {
        className = getBuilderClassNameByVersion(RestliVersion.RESTLI_2_0_0, null, resource.getName(), true);
    } else {
        className = getBuilderClassNameByVersion(RestliVersion.RESTLI_1_0_0, null, resource.getName(), true);
    }
    RootBuilderSpec rootBuilderSpec = null;
    if (resource.hasCollection()) {
        rootBuilderSpec = new CollectionRootBuilderSpec(resource);
    } else if (resource.hasSimple()) {
        rootBuilderSpec = new SimpleRootBuilderSpec(resource);
    } else if (resource.hasActionsSet()) {
        rootBuilderSpec = new ActionSetRootBuilderSpec(resource);
    } else {
        throw new IllegalArgumentException("unsupported resource type for resource: '" + resourceName + '\'');
    }
    rootBuilderSpec.setNamespace(packageName);
    rootBuilderSpec.setClassName(className);
    if (_version == RestliVersion.RESTLI_2_0_0) {
        rootBuilderSpec.setBaseClassName("BuilderBase");
    }
    rootBuilderSpec.setSourceIdlName(sourceFile);
    String resourcePath = getResourcePath(resource.getPath());
    rootBuilderSpec.setResourcePath(resourcePath);
    List<String> pathKeys = getPathKeys(resourcePath);
    rootBuilderSpec.setPathKeys(pathKeys);
    rootBuilderSpec.setParentRootBuilder(parentRootBuilder);
    StringArray supportsList = null;
    RestMethodSchemaArray restMethods = null;
    FinderSchemaArray finders = null;
    ResourceSchemaArray subresources = null;
    ActionSchemaArray resourceActions = null;
    ActionSchemaArray entityActions = null;
    String keyClass = null;
    if (resource.getCollection() != null) {
        CollectionSchema collection = resource.getCollection();
        String keyName = collection.getIdentifier().getName();
        // Complex key is not supported
        keyClass = collection.getIdentifier().getType();
        pathKeyTypes.put(keyName, collection.getIdentifier().getType());
        supportsList = collection.getSupports();
        restMethods = collection.getMethods();
        finders = collection.getFinders();
        subresources = collection.getEntity().getSubresources();
        resourceActions = collection.getActions();
        entityActions = collection.getEntity().getActions();
    } else if (resource.getSimple() != null) {
        SimpleSchema simpleSchema = resource.getSimple();
        keyClass = "Void";
        supportsList = simpleSchema.getSupports();
        restMethods = simpleSchema.getMethods();
        subresources = simpleSchema.getEntity().getSubresources();
        resourceActions = simpleSchema.getActions();
    } else if (resource.getActionsSet() != null) {
        ActionsSetSchema actionsSet = resource.getActionsSet();
        resourceActions = actionsSet.getActions();
    }
    Set<ResourceMethod> supportedMethods = getSupportedMethods(supportsList);
    if (!supportedMethods.isEmpty()) {
        for (ResourceMethod resourceMethod : supportedMethods) {
            validateResourceMethod(resource, resourceName, resourceMethod);
        }
    }
    List<RootBuilderMethodSpec> restMethodSpecs = new ArrayList<RootBuilderMethodSpec>();
    List<RootBuilderMethodSpec> finderSpecs = new ArrayList<RootBuilderMethodSpec>();
    List<RootBuilderMethodSpec> resourceActionSpecs = new ArrayList<RootBuilderMethodSpec>();
    List<RootBuilderMethodSpec> entityActionSpecs = new ArrayList<RootBuilderMethodSpec>();
    List<RootBuilderSpec> subresourceSpecs = new ArrayList<RootBuilderSpec>();
    String schemaClass = resource.getSchema();
    if (restMethods != null) {
        restMethodSpecs = generateBasicMethods(rootBuilderSpec, keyClass, schemaClass, supportedMethods, restMethods, resourceName, pathKeys, pathKeyTypes);
    }
    if (finders != null) {
        finderSpecs = generateFinders(rootBuilderSpec, finders, keyClass, schemaClass, resourceName, pathKeys, pathKeyTypes);
    }
    if (resourceActions != null) {
        resourceActionSpecs = generateActions(rootBuilderSpec, resourceActions, keyClass, resourceName, pathKeys, pathKeyTypes);
    }
    if (entityActions != null) {
        entityActionSpecs = generateActions(rootBuilderSpec, entityActions, keyClass, resourceName, pathKeys, pathKeyTypes);
    }
    if (subresources != null) {
        subresourceSpecs = generateSubResources(sourceFile, rootBuilderSpec, subresources, pathKeyTypes);
    }
    // assign to rootBuilderClass
    if (rootBuilderSpec instanceof CollectionRootBuilderSpec) {
        CollectionRootBuilderSpec rootBuilder = (CollectionRootBuilderSpec) rootBuilderSpec;
        rootBuilder.setRestMethods(restMethodSpecs);
        rootBuilder.setFinders(finderSpecs);
        rootBuilder.setResourceActions(resourceActionSpecs);
        rootBuilder.setEntityActions(entityActionSpecs);
        rootBuilder.setSubresources(subresourceSpecs);
    } else if (rootBuilderSpec instanceof SimpleRootBuilderSpec) {
        SimpleRootBuilderSpec rootBuilder = (SimpleRootBuilderSpec) rootBuilderSpec;
        rootBuilder.setRestMethods(restMethodSpecs);
        rootBuilder.setResourceActions(resourceActionSpecs);
        rootBuilder.setSubresources(subresourceSpecs);
    } else if (rootBuilderSpec instanceof ActionSetRootBuilderSpec) {
        ActionSetRootBuilderSpec rootBuilder = (ActionSetRootBuilderSpec) rootBuilderSpec;
        rootBuilder.setResourceActions(resourceActionSpecs);
    }
    registerBuilderSpec(rootBuilderSpec);
    return rootBuilderSpec;
}
Also used : RestMethodSchemaArray(com.linkedin.restli.restspec.RestMethodSchemaArray) CollectionSchema(com.linkedin.restli.restspec.CollectionSchema) SimpleSchema(com.linkedin.restli.restspec.SimpleSchema) ArrayList(java.util.ArrayList) ResourceSchemaArray(com.linkedin.restli.restspec.ResourceSchemaArray) ActionSetRootBuilderSpec(com.linkedin.restli.tools.clientgen.builderspec.ActionSetRootBuilderSpec) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) ActionsSetSchema(com.linkedin.restli.restspec.ActionsSetSchema) CollectionRootBuilderSpec(com.linkedin.restli.tools.clientgen.builderspec.CollectionRootBuilderSpec) StringArray(com.linkedin.data.template.StringArray) RootBuilderMethodSpec(com.linkedin.restli.tools.clientgen.builderspec.RootBuilderMethodSpec) FinderSchemaArray(com.linkedin.restli.restspec.FinderSchemaArray) ActionSchemaArray(com.linkedin.restli.restspec.ActionSchemaArray) RootBuilderSpec(com.linkedin.restli.tools.clientgen.builderspec.RootBuilderSpec) SimpleRootBuilderSpec(com.linkedin.restli.tools.clientgen.builderspec.SimpleRootBuilderSpec) CollectionRootBuilderSpec(com.linkedin.restli.tools.clientgen.builderspec.CollectionRootBuilderSpec) ActionSetRootBuilderSpec(com.linkedin.restli.tools.clientgen.builderspec.ActionSetRootBuilderSpec) SimpleRootBuilderSpec(com.linkedin.restli.tools.clientgen.builderspec.SimpleRootBuilderSpec) ResourceMethod(com.linkedin.restli.common.ResourceMethod)

Example 12 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class RestLiDataValidator method validatePatch.

/**
   * Checks that if the patch is applied to a valid entity, the modified entity will also be valid.
   * This method
   * (1) Checks that required/ReadOnly/CreateOnly fields are not deleted.
   * (2) Checks that new values for record templates contain all required fields.
   * (3) Applies the patch to an empty entity and validates the entity for custom validation rules
   * and Rest.li annotations (Allows required fields to be absent by using {@link RequiredMode#IGNORE},
   * because a patch does not necessarily contain all fields).
   *
   * NOTE: Updating a part of an array is not supported. So if the array contains a required field that is
   * readonly or createonly, the field cannot be present (no partial updates on readonly/createonly)
   * but cannot be absent either (no missing required fields). This means the array cannot be changed by a
   * partial update request. This is something that should be fixed.
   *
   * @param patchRequest the patch
   * @return the final validation result
   */
private ValidationResult validatePatch(PatchRequest<?> patchRequest) {
    // Instantiate an empty entity.
    RecordTemplate entity;
    try {
        entity = _valueClass.newInstance();
    } catch (InstantiationException e) {
        return validationResultWithErrorMessage(INSTANTIATION_ERROR);
    } catch (IllegalAccessException e) {
        return validationResultWithErrorMessage(ILLEGAL_ACCESS_ERROR);
    }
    // Apply the patch to the entity and get paths that $set and $delete operations were performed on.
    @SuppressWarnings("unchecked") PatchRequest<RecordTemplate> patch = (PatchRequest<RecordTemplate>) patchRequest;
    DataComplexProcessor processor = new DataComplexProcessor(new Patch(true), patch.getPatchDocument(), entity.data());
    MessageList<Message> messages;
    try {
        messages = processor.runDataProcessing(false);
    } catch (DataProcessingException e) {
        return validationResultWithErrorMessage("Error while applying patch: " + e.getMessage());
    }
    ValidationErrorResult checkDeleteResult = new ValidationErrorResult();
    checkDeletesAreValid(entity.schema(), messages, checkDeleteResult);
    if (!checkDeleteResult.isValid()) {
        return checkDeleteResult;
    }
    ValidationResult checkSetResult = checkNewRecordsAreNotMissingFields(entity, messages);
    if (checkSetResult != null) {
        return checkSetResult;
    }
    // It's okay if required fields are absent in a partial update request, so use ignore mode.
    return ValidateDataAgainstSchema.validate(new SimpleDataElement(entity.data(), entity.schema()), new ValidationOptions(RequiredMode.IGNORE), new DataValidator(entity.schema()));
}
Also used : Message(com.linkedin.data.message.Message) PatchRequest(com.linkedin.restli.common.PatchRequest) DataComplexProcessor(com.linkedin.data.transform.DataComplexProcessor) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) DataProcessingException(com.linkedin.data.transform.DataProcessingException) RecordTemplate(com.linkedin.data.template.RecordTemplate) SimpleDataElement(com.linkedin.data.element.SimpleDataElement) Patch(com.linkedin.data.transform.patch.Patch)

Example 13 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class RestLiDataValidator method checkNewRecordsAreNotMissingFields.

private ValidationResult checkNewRecordsAreNotMissingFields(RecordTemplate entity, MessageList<Message> messages) {
    for (Message message : messages) {
        Object[] path = message.getPath();
        if (path[path.length - 1].toString().equals(PatchConstants.SET_COMMAND)) {
            // Replace $set with the field name to get the full path
            path[path.length - 1] = message.getFormat();
            DataElement element = DataElementUtil.element(new SimpleDataElement(entity.data(), entity.schema()), path);
            ValidationResult result = ValidateDataAgainstSchema.validate(element, new ValidationOptions());
            if (!result.isValid()) {
                return result;
            }
        }
    }
    return null;
}
Also used : SimpleDataElement(com.linkedin.data.element.SimpleDataElement) DataElement(com.linkedin.data.element.DataElement) Message(com.linkedin.data.message.Message) SimpleDataElement(com.linkedin.data.element.SimpleDataElement) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions)

Example 14 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class RestLiDataValidator method validateInputEntity.

private ValidationResult validateInputEntity(RecordTemplate entity) {
    ValidationOptions validationOptions = new ValidationOptions();
    if (readOnlyOptional.contains(_resourceMethod)) {
        // Even if ReadOnly fields are non-optional, the client cannot supply them in a create request, so they should be treated as optional.
        validationOptions.setTreatOptional(_readOnlyPredicate);
    }
    ValidationResult result = ValidateDataAgainstSchema.validate(entity, validationOptions, new DataValidator(entity.schema()));
    return result;
}
Also used : ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) ValidationResult(com.linkedin.data.schema.validation.ValidationResult)

Example 15 with ValidationOptions

use of com.linkedin.data.schema.validation.ValidationOptions in project rest.li by linkedin.

the class TestFilters method testGetOldBuilders.

/**
   * This is a simple test that verifies the behavior of request and response filters. This test
   * hooks up two filters, one request filter and one response filter to the greeting resource.
   *
   * The behavior of the request filter is such that if the incoming request is of type create, the
   * filter modifies the incoming create request as follows:
   *
   * 1. If the tone of the incoming greeting is friendly, the filter modifies it to sincere.
   *
   * 2. If the tone of the incoming greeting is sincere, the filter modifies it to insulting.
   *
   * 3. If the tone of the incoming greeting is insulting, the filter throws an exception saying
   * that creation of a greeting with an insulting tone is not permitted. The HTTP status code is
   * set to 403.
   *
   * The behavior of the response filter is as follows:
   *
   * 1. If the response is an error, and the HTTP status code is 403, the filter updates the
   * outgoing error message and sets the status code to 400.
   *
   * 2. If the response is not an error, and the incoming request is a get, then the response filter
   * modifies the tone of the outgoing greeting message as follows:
   *
   * a. If the tone of the outgoing greeting from the resource is sincere, the filter modifies it to
   * friendly.
   *
   * b. If the tone of the outgoing greeting from the resource is insulting, the filter modifies it
   * to sincere.
   *
   * @param builders type of request builder.
   * @param tone tone of the greeting to be created.
   * @param responseFilter flag indicating whether or not the response filter is to be hooked up. NOTE: The
   *        request filter is always hooked up.
   * @param responseFilterException the exception the response filter will throw.
   * @throws Exception if anything unexpected happens.
   */
@Test(dataProvider = "requestBuilderDataProvider")
public void testGetOldBuilders(RootBuilderWrapper<Long, Greeting> builders, Tone tone, boolean responseFilter, RuntimeException responseFilterException) throws Exception {
    setupFilters(responseFilter, responseFilterException);
    Greeting greeting = generateTestGreeting("Test greeting.....", tone);
    Long createdId = null;
    try {
        createdId = createTestData(builders, greeting);
    } catch (RestLiResponseException e) {
        if (tone != Tone.INSULTING) {
            fail();
        }
        if (responseFilter) {
            assertEquals(e.getServiceErrorMessage(), RESP_FILTER_ERROR_MESSAGE);
            assertEquals(e.getResponse().getStatus(), RESP_FILTER_ERROR_STATUS.getCode());
        } else {
            assertEquals(e.getServiceErrorMessage(), REQ_FILTER_ERROR_MESSAGE);
            assertEquals(e.getResponse().getStatus(), REQ_FILTER_ERROR_STATUS.getCode());
        }
        verifyFilters(tone, responseFilter);
        return;
    }
    if (tone == Tone.INSULTING) {
        fail();
    }
    if (!responseFilter) {
        greeting.setTone(mapToneForIncomingRequest(tone));
    }
    greeting.setId(createdId);
    Request<Greeting> getRequest = builders.get().id(createdId).build();
    Greeting getReturnedGreeting = getClient().sendRequest(getRequest).getResponse().getEntity();
    ValidateDataAgainstSchema.validate(getReturnedGreeting.data(), getReturnedGreeting.schema(), new ValidationOptions());
    assertEquals(getReturnedGreeting, greeting);
    deleteAndVerifyTestData(builders, createdId);
    verifyFilters(tone, responseFilter);
}
Also used : Greeting(com.linkedin.restli.examples.greetings.api.Greeting) RestLiResponseException(com.linkedin.restli.client.RestLiResponseException) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) Test(org.testng.annotations.Test)

Aggregations

ValidationOptions (com.linkedin.data.schema.validation.ValidationOptions)29 ValidationResult (com.linkedin.data.schema.validation.ValidationResult)16 DataMap (com.linkedin.data.DataMap)13 Test (org.testng.annotations.Test)11 DataSchema (com.linkedin.data.schema.DataSchema)10 RecordDataSchema (com.linkedin.data.schema.RecordDataSchema)7 DataList (com.linkedin.data.DataList)4 RecordTemplate (com.linkedin.data.template.RecordTemplate)4 Greeting (com.linkedin.restli.examples.greetings.api.Greeting)4 ByteString (com.linkedin.data.ByteString)3 TestUtil.dataMapFromString (com.linkedin.data.TestUtil.dataMapFromString)3 TestUtil.dataSchemaFromString (com.linkedin.data.TestUtil.dataSchemaFromString)3 ArrayDataSchema (com.linkedin.data.schema.ArrayDataSchema)3 NamedDataSchema (com.linkedin.data.schema.NamedDataSchema)3 SchemaParser (com.linkedin.data.schema.SchemaParser)3 DataSchemaAnnotationValidator (com.linkedin.data.schema.validator.DataSchemaAnnotationValidator)3 DataElement (com.linkedin.data.element.DataElement)2 SimpleDataElement (com.linkedin.data.element.SimpleDataElement)2 Message (com.linkedin.data.message.Message)2 DataSchemaResolver (com.linkedin.data.schema.DataSchemaResolver)2