Search in sources :

Example 1 with Category

use of cern.modesti.schema.category.Category in project modesti by jlsalmon.

the class SchemaInitialiser method loadSchemas.

/**
 * Load all schemas inside plugins.
 *
 * @return the list of schemas that were found on the classpath
 * @throws IOException
 * @throws URISyntaxException
 */
private List<SchemaImpl> loadSchemas() throws IOException, URISyntaxException {
    List<SchemaImpl> schemas = new ArrayList<>();
    Map<String, List<SchemaImpl>> pluginSchemas = loadPluginSchemas();
    Map<String, List<CategoryImpl>> pluginCategories = loadPluginCategories();
    Map<String, List<DatasourceImpl>> pluginDatasources = loadPluginDatasources();
    for (Map.Entry<String, List<SchemaImpl>> entry : pluginSchemas.entrySet()) {
        for (SchemaImpl schema : entry.getValue()) {
            List<Category> categories = new ArrayList<>();
            List<Datasource> datasources = new ArrayList<>();
            // Skip over abstract schemas
            if (schema.isAbstract()) {
                continue;
            }
            // Merge in the parent schema if it is specified
            String parent = schema.getParent();
            if (parent != null) {
                Schema parentSchema = getSchema(pluginSchemas, parent);
                if (parentSchema == null) {
                    throw new IllegalArgumentException(format("Schema %s extends from unknown parent schema %s", schema.getId(), parent));
                }
                categories.addAll(parentSchema.getCategories());
                datasources.addAll(parentSchema.getDatasources());
                schema.setIdProperty(parentSchema.getIdProperty());
                schema.setSelectableStates(parentSchema.getSelectableStates());
                schema.setRowCommentStates(parentSchema.getRowCommentStates());
            }
            // Attach categories that are specified in the schema
            for (Category category : schema.getCategories()) {
                boolean categoryFound = false;
                for (Map.Entry<String, List<CategoryImpl>> categoryEntry : pluginCategories.entrySet()) {
                    if (categoryEntry.getValue().contains(category)) {
                        categories.add(categoryEntry.getValue().get(categoryEntry.getValue().indexOf(category)));
                        categoryFound = true;
                    }
                }
                if (!categoryFound) {
                    throw new IllegalArgumentException(format("Category %s was not found for schema %s", category.getId(), schema.getId()));
                }
            // TODO: support referencing another field by name to avoid duplicate field definitions
            }
            // Attach datasources that are specified in the schema
            for (Datasource datasource : schema.getDatasources()) {
                boolean datasourceFound = false;
                for (Map.Entry<String, List<DatasourceImpl>> datasourceEntry : pluginDatasources.entrySet()) {
                    if (datasourceEntry.getValue().contains(datasource)) {
                        datasources.add(datasourceEntry.getValue().get(datasourceEntry.getValue().indexOf(datasource)));
                        datasourceFound = true;
                    }
                }
                if (!datasourceFound) {
                    throw new IllegalArgumentException(format("Datasource %s was not found for schema %s", datasource.getId(), schema.getId()));
                }
            }
            // Process any overrides to the core categories
            for (Category override : schema.getOverrides()) {
                if (categories.contains(override)) {
                    Category overridden = mergeCategories(categories.get(categories.indexOf(override)), override);
                    categories.set(categories.indexOf(override), overridden);
                }
            }
            // Process any overrides to the core datasources
            for (Datasource override : schema.getDatasourceOverrides()) {
                if (datasources.contains(override)) {
                    Category overridden = mergeCategories(datasources.get(datasources.indexOf(override)), override);
                    datasources.set(datasources.indexOf(override), new DatasourceImpl((DatasourceImpl) overridden));
                }
            }
            schema.setCategories(categories);
            schema.setDatasources(datasources);
            // Invoke any post processors
            Map<String, SchemaPostProcessor> postProcessors = applicationContext.getBeansOfType(SchemaPostProcessor.class);
            for (SchemaPostProcessor postProcessor : postProcessors.values()) {
                schema = (SchemaImpl) postProcessor.postProcess(schema);
            }
            schemas.add(schema);
        }
    }
    String loadedPlugIns = schemas.stream().map(p -> p.getId()).collect(Collectors.joining(", "));
    log.trace("loaded {} schemas [{}]", schemas.size(), loadedPlugIns);
    return schemas;
}
Also used : Datasource(cern.modesti.schema.category.Datasource) java.util(java.util) URISyntaxException(java.net.URISyntaxException) Autowired(org.springframework.beans.factory.annotation.Autowired) SerializationUtils(org.apache.commons.lang3.SerializationUtils) PathMatchingResourcePatternResolver(org.springframework.core.io.support.PathMatchingResourcePatternResolver) URLConnection(java.net.URLConnection) JarURLConnection(java.net.JarURLConnection) Resource(org.springframework.core.io.Resource) DatasourceImpl(cern.modesti.schema.category.DatasourceImpl) SchemaPostProcessor(cern.modesti.schema.spi.SchemaPostProcessor) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) IOException(java.io.IOException) Datasource(cern.modesti.schema.category.Datasource) ApplicationContext(org.springframework.context.ApplicationContext) Collectors(java.util.stream.Collectors) File(java.io.File) StandardCharsets(java.nio.charset.StandardCharsets) String.format(java.lang.String.format) Slf4j(lombok.extern.slf4j.Slf4j) Component(org.springframework.stereotype.Component) Field(cern.modesti.schema.field.Field) ByteStreams(com.google.common.io.ByteStreams) PostConstruct(javax.annotation.PostConstruct) Category(cern.modesti.schema.category.Category) CategoryImpl(cern.modesti.schema.category.CategoryImpl) ResourcePatternResolver(org.springframework.core.io.support.ResourcePatternResolver) BeanUtils(org.springframework.beans.BeanUtils) Category(cern.modesti.schema.category.Category) SchemaPostProcessor(cern.modesti.schema.spi.SchemaPostProcessor) DatasourceImpl(cern.modesti.schema.category.DatasourceImpl)

Example 2 with Category

use of cern.modesti.schema.category.Category in project modesti by jlsalmon.

the class CoreValidationService method validatePoints.

private boolean validatePoints(Request request, List<Category> categories) {
    boolean valid = true;
    for (Point point : request.getNonEmptyPoints()) {
        for (Category category : categories) {
            for (Field field : category.getFields()) {
                Object value = point.getValueByPropertyName(field.getPropertyName());
                // Check for invalid fields
                if (!isValidValue(value, point, field)) {
                    point.setValid(false);
                    valid = false;
                    point.addErrorMessage(category.getId(), field.getId(), "Value '" + value + "' is not a legal option for field '" + field.getName() + "'. Please select a value from the list.");
                }
                // Validate unique fields
                if (field.getUnique() != null) {
                    Constraint constraint = new Constraint("unique", Collections.singletonList(field.getId()), null);
                    if (!Constraints.validate(constraint, request, category)) {
                        valid = false;
                    }
                }
                // Required fields (can be simple boolean or condition list)
                boolean required = false;
                if (field.getRequired() instanceof Boolean && (Boolean) field.getRequired()) {
                    required = true;
                } else if (field.getRequired() != null) {
                    required = Conditionals.evaluate(field.getRequired(), point, request);
                }
                if (required) {
                    if (value == null || value.equals("")) {
                        point.setValid(false);
                        valid = false;
                        point.addErrorMessage(category.getId(), field.getId(), "'" + field.getName() + "' is mandatory");
                    }
                }
                // Min length
                if (field.getMinLength() != null) {
                    if (value != null && value.toString().length() < field.getMinLength()) {
                        point.setValid(false);
                        valid = false;
                        point.addErrorMessage(category.getId(), field.getId(), "'" + field.getName() + "' must be at least " + field.getMinLength() + " characters in length");
                    }
                }
                // Max length
                if (field.getMaxLength() != null) {
                    if (value != null && value.toString().length() > field.getMaxLength()) {
                        point.setValid(false);
                        valid = false;
                        point.addErrorMessage(category.getId(), field.getId(), "'" + field.getName() + "' must not exceed " + field.getMaxLength() + " characters in length");
                    }
                }
                // Numeric fields
                if (field.getType().equals("numeric")) {
                    if (value != null && !value.toString().isEmpty() && !NumberUtils.isNumber(value.toString())) {
                        point.setValid(false);
                        valid = false;
                        point.addErrorMessage(category.getId(), field.getId(), "Value for '" + field.getName() + "' must be numeric");
                    }
                }
            }
        }
    }
    return valid;
}
Also used : AutocompleteField(cern.modesti.schema.field.AutocompleteField) Field(cern.modesti.schema.field.Field) OptionsField(cern.modesti.schema.field.OptionsField) Category(cern.modesti.schema.category.Category) Constraint(cern.modesti.schema.category.Constraint) Point(cern.modesti.point.Point)

Example 3 with Category

use of cern.modesti.schema.category.Category in project modesti by jlsalmon.

the class CoreValidationService method validateRequest.

public boolean validateRequest(Request request) {
    try {
        if (RequestType.DELETE.equals(request.getType())) {
            // Delete requests should not be validated
            return true;
        }
        boolean valid = true;
        Schema schema = schemaRepository.findOne(request.getDomain());
        // Reset all points and clear any error messages.
        for (Point point : request.getPoints()) {
            point.setValid(true);
            point.setErrors(new ArrayList<>());
        }
        if (environment.getProperty("modesti.disableValidator", Boolean.class, false) || request.isSkipCoreValidation()) {
            log.info("core validations disabled");
        } else {
            // Concatenate all categories and datasources
            List<Category> categories = new ArrayList<>(schema.getCategories());
            categories.addAll(schema.getDatasources());
            // Validate the mutually exclusive column group specifications.
            if (!validateMutualExclusions(request, categories)) {
                valid = false;
            }
            // column groups and mutually inclusive fields.
            if (!validateConstraints(request, categories)) {
                valid = false;
            }
            // values, min/max length, valid values etc.
            if (!validatePoints(request, categories)) {
                valid = false;
            }
        }
        request.setValid(valid);
        requestService.save(request);
        if (!valid) {
            log.info(format("request #%s failed validation, not invoking custom validator", request.getRequestId()));
            return false;
        }
        log.info(format("request #%s is valid, invoking custom validator", request.getRequestId()));
        RequestProvider plugin = requestProviderRegistry.getPluginFor(request);
        RequestValidator validator = getPluginRequestValidator(plugin.getMetadata().getId());
        if (validator == null) {
            log.info(format("custom validator not provided for request #%s", request.getRequestId()));
            return true;
        }
        valid = validator.validateRequest(request, schema);
        request.setValid(valid);
        requestService.save(request);
        return valid;
    } catch (RuntimeException e) {
        request.setValid(false);
        requestService.save(request);
        log.info(format("Unexpected error during validation phase for request #%s '%s'", request.getRequestId(), e.toString()), e);
        return false;
    }
}
Also used : Category(cern.modesti.schema.category.Category) Schema(cern.modesti.schema.Schema) ArrayList(java.util.ArrayList) RequestProvider(cern.modesti.plugin.RequestProvider) Point(cern.modesti.point.Point)

Example 4 with Category

use of cern.modesti.schema.category.Category in project modesti by jlsalmon.

the class CoreValidationService method validateMutualExclusions.

private boolean validateMutualExclusions(Request request, List<Category> categories) {
    boolean valid = true;
    for (Category category : categories) {
        if (category.getExcludes() == null) {
            continue;
        }
        for (String exclude : category.getExcludes()) {
            // Get the excluded category
            for (Category cat : categories) {
                if (cat.getId().equals(exclude)) {
                    Category excludedCategory = cat;
                    // so, say something like "Fields in the "Alarms" group cannot be used if fields in the "Commands" group have been specified.".
                    for (Point point : request.getNonEmptyPoints()) {
                        List<Field> emptyFields = point.getEmptyFields(category.getFields());
                        // If at least one of the fields of this category are filled, then we must check the excluded category.
                        if (emptyFields.size() != category.getFields().size()) {
                            emptyFields = point.getEmptyFields(excludedCategory.getFields());
                            if (emptyFields.size() != excludedCategory.getFields().size()) {
                                point.setValid(false);
                                valid = false;
                                point.addErrorMessage(category.getId(), "", "Fields in the '" + category.getName() + "' group cannot be used if fields in the '" + excludedCategory.getName() + "' group have been specified.");
                            }
                        }
                    }
                }
            }
        }
    }
    return valid;
}
Also used : AutocompleteField(cern.modesti.schema.field.AutocompleteField) Field(cern.modesti.schema.field.Field) OptionsField(cern.modesti.schema.field.OptionsField) Category(cern.modesti.schema.category.Category) Point(cern.modesti.point.Point)

Aggregations

Category (cern.modesti.schema.category.Category)4 Point (cern.modesti.point.Point)3 Field (cern.modesti.schema.field.Field)3 AutocompleteField (cern.modesti.schema.field.AutocompleteField)2 OptionsField (cern.modesti.schema.field.OptionsField)2 RequestProvider (cern.modesti.plugin.RequestProvider)1 Schema (cern.modesti.schema.Schema)1 CategoryImpl (cern.modesti.schema.category.CategoryImpl)1 Constraint (cern.modesti.schema.category.Constraint)1 Datasource (cern.modesti.schema.category.Datasource)1 DatasourceImpl (cern.modesti.schema.category.DatasourceImpl)1 SchemaPostProcessor (cern.modesti.schema.spi.SchemaPostProcessor)1 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)1 ByteStreams (com.google.common.io.ByteStreams)1 File (java.io.File)1 IOException (java.io.IOException)1 String.format (java.lang.String.format)1 JarURLConnection (java.net.JarURLConnection)1 URISyntaxException (java.net.URISyntaxException)1 URLConnection (java.net.URLConnection)1