org.wrml.runtime.format.application.schema.json.JsonSchemaLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.wrml.runtime.format.application.schema.json.JsonSchemaLoader.java

Source

/**
 * WRML - Web Resource Modeling Language
 *  __     __   ______   __    __   __
 * /\ \  _ \ \ /\  == \ /\ "-./  \ /\ \
 * \ \ \/ ".\ \\ \  __< \ \ \-./\ \\ \ \____
 *  \ \__/".~\_\\ \_\ \_\\ \_\ \ \_\\ \_____\
 *   \/_/   \/_/ \/_/ /_/ \/_/  \/_/ \/_____/
 *
 * http://www.wrml.org
 *
 * Copyright (C) 2011 - 2013 Mark Masse <mark@wrml.org> (OSS project WRML.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.wrml.runtime.format.application.schema.json;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.wrml.model.MaybeRequired;
import org.wrml.model.rest.LinkRelation;
import org.wrml.model.schema.*;
import org.wrml.runtime.*;
import org.wrml.runtime.format.application.schema.json.JsonSchema.Definitions.JsonType;
import org.wrml.runtime.format.application.schema.json.JsonSchema.Definitions.PropertyType;
import org.wrml.runtime.format.application.schema.json.JsonSchema.JsonStringFormat;
import org.wrml.runtime.schema.SchemaLoader;
import org.wrml.runtime.syntax.SyntaxLoader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;

public class JsonSchemaLoader implements Loader {

    private Context _Context;

    private final ConcurrentHashMap<URI, JsonSchema> _JsonSchemas;

    public JsonSchemaLoader() {

        _JsonSchemas = new ConcurrentHashMap<URI, JsonSchema>();
    }

    public static void main(final String[] args) throws Exception {

        final String wrmlConfigFilePath = args[0];
        final EngineConfiguration config = EngineConfiguration.load(wrmlConfigFilePath);
        final Engine engine = new DefaultEngine();
        engine.init(config);

        final String urlString = args[1];
        final URL jsonSchemaId = new URL(urlString);

        final SchemaLoader schemaLoader = engine.getContext().getSchemaLoader();

        final JsonSchemaLoader jsonSchemaLoader = schemaLoader.getJsonSchemaLoader();
        final JsonSchema downloadedJsonSchema = jsonSchemaLoader.load(jsonSchemaId);
        System.out.println("Downloaded JSON schema:\n" + downloadedJsonSchema);

        final Schema schema = schemaLoader.load(downloadedJsonSchema, schemaLoader.getDocumentSchemaUri());
        System.out.println("Generated WRML schema:\n" + schema);

        final Schema docSchema = schemaLoader.load(schemaLoader.getDocumentSchemaUri());
        final JsonSchema docJsonSchema = jsonSchemaLoader.load(docSchema);
        System.out.println("Generated WRML's Document schema as a JSON schema:\n" + docJsonSchema);

    }

    public JsonSchema getLoadedJsonSchema(final URI schemaUri) {

        if (_JsonSchemas.containsKey(schemaUri)) {
            return _JsonSchemas.get(schemaUri);
        }
        return null;
    }

    public SortedSet<URI> getLoadedJsonSchemaUris() {

        return new TreeSet<URI>(_JsonSchemas.keySet());
    }

    public JsonSchema load(final File file) throws IOException {

        if (file == null) {
            throw new FileNotFoundException("The JSON schema file is null.");
        }

        if (!file.exists()) {
            throw new FileNotFoundException(
                    "The JSON schema file named \"" + file.getAbsolutePath() + "\" does not exist.");
        }

        final InputStream in = FileUtils.openInputStream(file);
        final JsonSchema jsonSchema = load(in, null);
        IOUtils.closeQuietly(in);
        return jsonSchema;
    }

    public JsonSchema load(final InputStream in, final URI jsonSchemaId) throws IOException {

        final ObjectNode rootNode = new ObjectMapper().readValue(in, ObjectNode.class);
        return load(rootNode, jsonSchemaId);
    }

    public JsonSchema load(final ObjectNode rootNode, final URI jsonSchemaId) {

        final URI jsonSchemaIdPropertyValue = PropertyType.Id.getValue(rootNode, getSyntaxLoader());
        final URI id = (jsonSchemaIdPropertyValue != null) ? jsonSchemaIdPropertyValue : jsonSchemaId;

        if (id == null) {
            throw new JsonSchemaLoaderException("The JSON Schema \"id\" slot value (URI) could not be determined.",
                    null, this);

        }

        PropertyType.Id.setValue(rootNode, id, getSyntaxLoader());

        final JsonSchema jsonSchema = new JsonSchema(this, rootNode);

        _JsonSchemas.put(id, jsonSchema);

        return jsonSchema;

    }

    public JsonSchema load(final Schema wrmlSchema) {

        if (wrmlSchema == null) {
            return null;
        }

        final URI schemaUri = wrmlSchema.getUri();
        if (_JsonSchemas.containsKey(schemaUri)) {
            return _JsonSchemas.get(schemaUri);
        }

        final String schemaTitle = wrmlSchema.getTitle();
        final String schemaDescription = wrmlSchema.getDescription();

        final ObjectNode schemaNode = JsonNodeFactory.instance.objectNode();

        PropertyType.Id.setValue(schemaNode, schemaUri, getSyntaxLoader());
        PropertyType.Title.setValue(schemaNode, schemaTitle, getSyntaxLoader());
        PropertyType.Description.setValue(schemaNode, schemaDescription, getSyntaxLoader());
        PropertyType.Type.setValue(schemaNode, JsonType.Object.getKeyword(), getSyntaxLoader());

        initStringArrayNode(schemaNode, PropertyType.Extends.getName(), wrmlSchema.getBaseSchemaUris());

        initStringArrayNode(schemaNode, Schema.SLOT_NAME_KEY_SLOT_NAMES, wrmlSchema.getKeySlotNames());

        // TODO
        // wrmlSchema.getVersion();

        final ObjectNode propertiesNode = schemaNode.putObject(PropertyType.Properties.getName());
        final List<Slot> slots = wrmlSchema.getSlots();
        for (final Slot slot : slots) {

            final Value value = slot.getValue();
            if (value instanceof LinkValue) {
                initLinkSlotNode(schemaNode, slot);
            } else {
                final String slotName = slot.getName();
                final ObjectNode slotNode = propertiesNode.putObject(slotName);

                initPropertySlotNode(slotNode, slot);
            }

        }

        return load(schemaNode, schemaUri);
    }

    private void initStringArrayNode(final ObjectNode node, final String arrayNodeName,
            Collection<?> arrayNodeElements) {

        if (arrayNodeElements == null || arrayNodeElements.isEmpty() || arrayNodeName == null) {
            return;
        }

        final ArrayNode arrayNode = node.putArray(arrayNodeName);

        final SyntaxLoader syntaxLoader = getSyntaxLoader();
        for (Object element : arrayNodeElements) {
            final String stringValue = syntaxLoader.formatSyntaxValue(element);
            arrayNode.add(stringValue);
        }

    }

    public JsonSchema load(final URI jsonSchemaUri) throws IOException {

        if (_JsonSchemas.containsKey(jsonSchemaUri)) {
            return _JsonSchemas.get(jsonSchemaUri);
        }

        final ObjectNode rootNode = new ObjectMapper().readValue(jsonSchemaUri.toURL(), ObjectNode.class);
        return load(rootNode, jsonSchemaUri);
    }

    public JsonSchema load(final URL jsonSchemaUrl) throws IOException {

        final URI jsonSchemaUri = URI.create(jsonSchemaUrl.toString());
        if (_JsonSchemas.containsKey(jsonSchemaUri)) {
            return _JsonSchemas.get(jsonSchemaUri);
        }

        final ObjectNode rootNode = new ObjectMapper().readValue(jsonSchemaUrl, ObjectNode.class);
        return load(rootNode, jsonSchemaUri);
    }

    private JsonType getJsonType(final Value value) {

        final JsonType jsonType;

        if (value instanceof TextValue) {
            jsonType = JsonType.String;
        } else if (value instanceof ListValue) {
            jsonType = JsonType.Array;
        } else if (value instanceof ModelValue) {
            jsonType = JsonType.Object;
        } else if (value instanceof IntegerValue) {
            jsonType = JsonType.Integer;
        } else if (value instanceof BooleanValue) {
            jsonType = JsonType.Boolean;
        } else if (value instanceof DoubleValue || value instanceof LongValue) {
            jsonType = JsonType.Number;
        } else if (value instanceof DateValue || value instanceof SingleSelectValue) {
            jsonType = JsonType.String;
        } else if (value instanceof LinkValue) {
            jsonType = null;
        } else {
            jsonType = JsonType.Any;
        }

        return jsonType;
    }

    private void initLinkSlotNode(final ObjectNode schemaNode, final Slot slot) {

        ArrayNode linksArrayNode = PropertyType.Links.getValueNode(schemaNode);
        if (linksArrayNode == null) {
            linksArrayNode = schemaNode.putArray(PropertyType.Links.getName());
        }

        final LinkValue linkValue = (LinkValue) slot.getValue();
        final ObjectNode linkNode = linksArrayNode.addObject();
        PropertyType.Type.setValue(linkNode, JsonType.Object.getKeyword(), getSyntaxLoader());

        final URI linkRelationUri = linkValue.getLinkRelationUri();
        final LinkRelation linkRelation = linkValue.getContext().getApiLoader().loadLinkRelation(linkRelationUri);
        if (linkRelation != null) {

            PropertyType.Rel.setValue(linkNode, linkRelation.getUniqueName().getLocalName(), getSyntaxLoader());

            PropertyType.Method.setValue(linkNode, linkRelation.getMethod().getProtocolGivenName(),
                    getSyntaxLoader());
        }

        final URI responseSchemaUri = linkValue.getResponseSchemaUri();
        if (responseSchemaUri != null) {
            final ObjectNode targetSchemaNode = linkNode.putObject(PropertyType.TargetSchema.getName());
            PropertyType.Type.setValue(targetSchemaNode, JsonType.Object.getKeyword(), getSyntaxLoader());
            PropertyType.$Ref.setValue(targetSchemaNode, responseSchemaUri, getSyntaxLoader());
        }

        final URI requestSchemaUri = linkValue.getRequestSchemaUri();
        if (requestSchemaUri != null) {
            final ObjectNode paramSchemaNode = linkNode.putObject(PropertyType.Schema.getName());
            PropertyType.Type.setValue(paramSchemaNode, JsonType.Object.getKeyword(), getSyntaxLoader());
            PropertyType.$Ref.setValue(paramSchemaNode, requestSchemaUri, getSyntaxLoader());
        }

    }

    private void initPropertySlotNode(final ObjectNode slotNode, final Slot slot) {

        final Value value = slot.getValue();

        PropertyType.Title.setValue(slotNode, slot.getTitle(), getSyntaxLoader());
        PropertyType.Description.setValue(slotNode, slot.getDescription(), getSyntaxLoader());
        final JsonType valueJsonType = getJsonType(value);

        if (valueJsonType != null) {
            PropertyType.Type.setValue(slotNode, valueJsonType.getKeyword(), getSyntaxLoader());
        }

        if (value instanceof TextValue) {
            final TextValue textValue = (TextValue) value;
            final URI syntaxUri = textValue.getSyntaxUri();
            if (syntaxUri != null) {
                final Context context = slot.getContext();
                final SyntaxLoader syntaxLoader = context.getSyntaxLoader();
                final Class<?> syntaxJavaClass = syntaxLoader.getSyntaxJavaClass(syntaxUri);
                if (syntaxJavaClass != null) {
                    final JsonStringFormat jsonStringFormat = JsonStringFormat.forJavaType(syntaxJavaClass);
                    if (jsonStringFormat != null) {
                        PropertyType.Format.setValue(slotNode, jsonStringFormat.getKeyword(), getSyntaxLoader());
                    }
                }
            }

            PropertyType.MaxLength.setValue(slotNode, value.getSlotValue(TextValue.SLOT_NAME_MAXIMUM_LENGTH),
                    getSyntaxLoader());

            PropertyType.MinLength.setValue(slotNode, value.getSlotValue(TextValue.SLOT_NAME_MINIMUM_LENGTH),
                    getSyntaxLoader());

        } else if (value instanceof ListValue) {
            final ListValue listValue = (ListValue) value;
            final ArrayNode arrayNode = slotNode.putArray(PropertyType.Items.getName());
            final ObjectNode itemSlotNode = arrayNode.addObject();
            initPropertySlotNode(itemSlotNode, listValue.getElementSlot());

            PropertyType.MaxItems.setValue(slotNode, value.getSlotValue(ListValue.SLOT_NAME_MAXIMUM_SIZE),
                    getSyntaxLoader());

            PropertyType.MinItems.setValue(slotNode, value.getSlotValue(ListValue.SLOT_NAME_MINIMUM_SIZE),
                    getSyntaxLoader());

            PropertyType.UniqueItems.setValue(slotNode,
                    value.getSlotValue(ListValue.SLOT_NAME_ELEMENT_UNIQUENESS_CONSTRAINED), getSyntaxLoader());

        } else if (value instanceof ModelValue) {
            final ModelValue modelValue = (ModelValue) value;
            PropertyType.$Ref.setValue(slotNode, modelValue.getModelSchemaUri(), getSyntaxLoader());
        } else if (value instanceof NumericValue) {
            PropertyType.Maximum.setValue(slotNode, value.getSlotValue(NumericValue.SLOT_NAME_MAXIMUM),
                    getSyntaxLoader());

            PropertyType.Minimum.setValue(slotNode, value.getSlotValue(NumericValue.SLOT_NAME_MINIMUM),
                    getSyntaxLoader());

        }

        if (value instanceof MaybeRequired) {
            PropertyType.Required.setValue(slotNode, value.getSlotValue(MaybeRequired.SLOT_NAME_REQUIRED),
                    getSyntaxLoader());
        }

        if (value.containsSlotValue(Value.SLOT_NAME_DEFAULT)) {
            PropertyType.Default.setValue(slotNode, value.getSlotValue(Value.SLOT_NAME_DEFAULT), getSyntaxLoader());
        }

    }

    private SyntaxLoader getSyntaxLoader() {

        return getContext().getSyntaxLoader();
    }

    @Override
    public void loadInitialState() {

    }

    @Override
    public Context getContext() {

        return _Context;
    }

    @Override
    public void init(final Context context) {

        if (context == null) {
            throw new JsonSchemaLoaderException("The context cannot be null.", null, this);
        }

        _Context = context;

    }
}