Package uk.co.o2.json.schema

Source Code of uk.co.o2.json.schema.SchemaCompiler$ProcessedSchemaEntry

package uk.co.o2.json.schema;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import uk.co.o2.json.schema.ObjectSchema.Property;


class SchemaCompiler {
    private final SchemaPassThroughCache cache;
    private final JsonFactory jsonFactory;
    private final Queue<ProcessingEntry> schemasToCompile = new LinkedList<>();

    public SchemaCompiler(SchemaPassThroughCache cache, JsonFactory jsonFactory) {
        this.cache = cache;
        this.jsonFactory = jsonFactory;
    }

    public JsonSchema parse(URL schemaLocation) {

        List<ProcessedSchemaEntry> compiledSchemasToRegister = new ArrayList<>();

        scheduleSchemaForProcessing(schemaLocation);

        ProcessingEntry entry = schemasToCompile.peek();
        while (entry != null) {
            JsonSchema compiledSchema = parse(entry.rawSchema, entry.schemaLocation);
            compiledSchemasToRegister.add(new ProcessedSchemaEntry(entry.schemaLocation, compiledSchema));

            schemasToCompile.poll();
            entry = schemasToCompile.peek();
        }

        for (ProcessedSchemaEntry schemaToRegister : compiledSchemasToRegister) {
            cache.registerSchema(schemaToRegister.schemaLocation, schemaToRegister.compiledSchema);
        }

        return cache.getSchema(schemaLocation);
    }

    private void scheduleSchemaForProcessing(URL schemaLocation) {
        if (cache.hasSchema(schemaLocation)) {
            return; //schema has already been compiled before, or on another thread
        }

        for (ProcessingEntry it : schemasToCompile) {
            if (it.schemaLocation.toString().equals(schemaLocation.toString())) {
                return; //schema is already scheduled for compilation
            }
        }

        try {
            JsonParser parser = jsonFactory.createJsonParser(schemaLocation);
            try {
                JsonNode rawSchema = parser.readValueAsTree();
                schemasToCompile.add(new ProcessingEntry(schemaLocation, rawSchema));
            } finally {
                parser.close();
            }
        } catch (JsonParseException jpe) {
            throw new IllegalArgumentException("The schema at location " + schemaLocation.toString() + " contains invalid JSON", jpe);
        } catch (IOException ioe) {
            throw new IllegalArgumentException("Could not retrieve schema from " + schemaLocation.toString(), ioe);
        }
    }

    private JsonSchema parse(JsonNode rawSchema, URL currentSchemaLocation) {
        if (!rawSchema.isObject()) {
            throw new IllegalArgumentException("A valid json schema must be an object");
        }

        JsonNode ref = rawSchema.get("$ref");
        if (ref != null) {
            URL referencedSchemaLocation;
            try {
                referencedSchemaLocation = new URL(currentSchemaLocation, ref.textValue());
            } catch (MalformedURLException e) {
                throw new IllegalArgumentException("The schema reference is malformed", e);
            }
            scheduleSchemaForProcessing(referencedSchemaLocation);
            return new SchemaReference(cache, referencedSchemaLocation);
        }

        String type = rawSchema.get("type").asText();
        if (isSimpleTypeSchema(type)) {
            return parseSimpleTypeSchema(rawSchema);
        } else if (isObjectSchema(type)) {
            return parseObjectSchema(rawSchema, currentSchemaLocation);
        } else if (isArraySchema(type)) {
            return parseArraySchema(rawSchema, currentSchemaLocation);
        }
        throw new IllegalArgumentException("Illegal schema type " + type);
    }

    private boolean isArraySchema(String type) {
        return "array".equals(type);
    }

    private boolean isObjectSchema(String type) {
        return "object".equals(type);
    }

    private boolean isSimpleTypeSchema(String type) {
        for (SimpleType it : SimpleType.values()) {
            if (it.name().equals(type.toUpperCase())) {
                return true;
            }
        }
        return false;
    }

    private SimpleTypeSchema parseSimpleTypeSchema(JsonNode rawSchema) {
        SimpleTypeSchema result = new SimpleTypeSchema();
        result.setType(SimpleType.valueOf(rawSchema.get("type").asText().toUpperCase()));

        JsonNode pattern = rawSchema.get("pattern");
        if (pattern != null) {
            result.setPattern(Pattern.compile(pattern.textValue()));
        }

        JsonNode minLength = rawSchema.get("minLength");
        if (minLength != null) {
            result.setMinLength(minLength.intValue());
        }

        JsonNode maxLength = rawSchema.get("maxLength");
        if (maxLength != null) {
            result.setMaxLength(maxLength.intValue());
        }

        JsonNode minimum = rawSchema.get("minimum");
        if (minimum != null) {
            result.setMinimum(minimum.decimalValue());
        }

        JsonNode maximum = rawSchema.get("maximum");
        if (maximum != null) {
            result.setMaximum(maximum.decimalValue());
        }

        JsonNode exclusiveMinimum = rawSchema.get("exclusiveMinimum");
        if (exclusiveMinimum != null) {
            result.setExclusiveMinimum(exclusiveMinimum.booleanValue());
        }

        JsonNode exclusiveMaximum = rawSchema.get("exclusiveMaximum");
        if (exclusiveMaximum != null) {
            result.setExclusiveMaximum(exclusiveMaximum.booleanValue());
        }

        JsonNode enumeration = rawSchema.get("enumeration");
        if (enumeration != null) {
            List<JsonNode> enumerationValues = new ArrayList<>();
            for (JsonNode node : enumeration) {
                enumerationValues.add(node);
            }
            result.setEnumeration(enumerationValues);
        }

        JsonNode format = rawSchema.get("format");
        if (format!= null) {
            result.setFormat(format.textValue());
        }
        return result;
    }

    private ArraySchema parseArraySchema(JsonNode rawSchema, URL schemaLocation) {
        ArraySchema result = new ArraySchema();
        JsonNode rawItems = rawSchema.get("items");
        if (rawItems != null) {
            result.setItems(parse(rawItems, schemaLocation));
        }
        JsonNode rawMinItems = rawSchema.get("minItems");
        if (rawMinItems != null) {
            result.setMinItems(rawMinItems.intValue());
        }
        JsonNode rawMaxItems = rawSchema.get("maxItems");
        if (rawMaxItems != null) {
            result.setMaxItems(rawMaxItems.intValue());
        }
        return result;
    }

    private ObjectSchema parseObjectSchema(JsonNode rawSchema, URL schemaLocation) {
        ObjectSchema result = new ObjectSchema();
        configureAdditionalPropertiesForObjectSchema(rawSchema.get("additionalProperties"), result, schemaLocation);
        configurePropertiesForObjectSchema(rawSchema.get("properties"), result, schemaLocation);
        return result;
    }

    private void configureAdditionalPropertiesForObjectSchema(JsonNode additionalProperties, ObjectSchema schema, URL schemaLocation) {
        if (additionalProperties == null) {
            return;
        }
        if (additionalProperties.isBoolean()) {
            JsonSchema additionalPropertiesSchema = additionalProperties.booleanValue() ? ObjectSchema.ALLOW_ALL_ADDITIONAL_PROPERTIES : ObjectSchema.FORBID_ANY_ADDITIONAL_PROPERTIES;
            schema.setAdditionalProperties(additionalPropertiesSchema);
        } else {
            schema.setAdditionalProperties(parse(additionalProperties, schemaLocation));
        }
    }

    private void configurePropertiesForObjectSchema(JsonNode rawProperties, ObjectSchema schema, URL schemaLocation) {
        if (rawProperties == null) {
            return;
        }

        for (Iterator<String> iterator = rawProperties.fieldNames(); iterator.hasNext();) {
            String fieldName = iterator.next();

            Property property = new Property();
            property.setName(fieldName);
           
            JsonNode nestedSchema = rawProperties.get(fieldName);
            property.setNestedSchema(parse(nestedSchema, schemaLocation));

            JsonNode required = nestedSchema.get("required");
            if (required != null) {
                property.setRequired(required.booleanValue());
            }
           
            schema.getProperties().add(property);
        }
    }

    private static class ProcessingEntry {
        final URL schemaLocation;
        final JsonNode rawSchema;

        ProcessingEntry(URL schemaLocation, JsonNode rawSchema) {
            this.schemaLocation = schemaLocation;
            this.rawSchema = rawSchema;
        }
    }

    private static class ProcessedSchemaEntry {
        final URL schemaLocation;
        final JsonSchema compiledSchema;

        ProcessedSchemaEntry(URL schemaLocation, JsonSchema compiledSchema) {
            this.schemaLocation = schemaLocation;
            this.compiledSchema = compiledSchema;
        }
    }
}
TOP

Related Classes of uk.co.o2.json.schema.SchemaCompiler$ProcessedSchemaEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.