com.github.fge.jsonschema.core.load.configuration.LoadingConfigurationBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.github.fge.jsonschema.core.load.configuration.LoadingConfigurationBuilder.java

Source

/*
 * Copyright (c) 2014, Francis Galiegue (fgaliegue@gmail.com)
 *
 * This software is dual-licensed under:
 *
 * - the Lesser General Public License (LGPL) version 3.0 or, at your option, any
 *   later version;
 * - the Apache Software License (ASL) version 2.0.
 *
 * The text of this file and of both licenses is available at the root of this
 * project or, if you have the jar distribution, in directory META-INF/, under
 * the names LGPL-3.0.txt and ASL-2.0.txt respectively.
 *
 * Direct link to the sources:
 *
 * - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
 * - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
 */

package com.github.fge.jsonschema.core.load.configuration;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.Thawed;
import com.github.fge.jsonschema.SchemaVersion;
import com.github.fge.jsonschema.core.exceptions.JsonReferenceException;
import com.github.fge.jsonschema.core.load.Dereferencing;
import com.github.fge.jsonschema.core.load.SchemaLoader;
import com.github.fge.jsonschema.core.load.URIManager;
import com.github.fge.jsonschema.core.load.uri.URITranslatorConfiguration;
import com.github.fge.jsonschema.core.load.download.URIDownloader;
import com.github.fge.jsonschema.core.messages.JsonSchemaCoreMessageBundle;
import com.github.fge.jsonschema.core.ref.JsonRef;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;
import com.google.common.collect.Maps;

import java.net.URI;
import java.util.EnumSet;
import java.util.Map;

import static com.fasterxml.jackson.core.JsonParser.*;

/**
 * Loading configuration (mutable instance)
 *
 * @see LoadingConfiguration
 */
public final class LoadingConfigurationBuilder implements Thawed<LoadingConfiguration> {
    private static final MessageBundle BUNDLE = MessageBundles.getBundle(JsonSchemaCoreMessageBundle.class);

    /**
     * Default JsonParser feature set. Unfortunately, Jackson does not use
     * EnumSets to collect them, so we have to do that...
     */
    private static final EnumSet<JsonParser.Feature> DEFAULT_PARSER_FEATURES;

    static {
        DEFAULT_PARSER_FEATURES = EnumSet.noneOf(JsonParser.Feature.class);

        for (final JsonParser.Feature feature : JsonParser.Feature.values())
            if (feature.enabledByDefault())
                DEFAULT_PARSER_FEATURES.add(feature);
    }

    /**
     * Mutable map of URI downloaders
     *
     * @see URIDownloader
     * @see URIManager
     * @see URIDownloadersRegistry
     */
    final URIDownloadersRegistry downloaders = new URIDownloadersRegistry();

    URITranslatorConfiguration translatorCfg;

    /**
     * Loaded schemas are cached by default
     */
    boolean enableCache = true;

    /**
     * Dereferencing mode
     *
     * @see SchemaLoader
     */
    Dereferencing dereferencing;

    /**
     * List of preloaded schemas
     *
     * <p>The default list of preloaded schemas consists of the draft v3 and
     * draft v4 core schemas</p>
     *
     * @see SchemaVersion
     */
    final Map<URI, JsonNode> preloadedSchemas;

    /**
     * Set of JsonParser features to be enabled while loading schemas
     */
    final EnumSet<JsonParser.Feature> parserFeatures;

    /**
     * Return a new, default mutable loading configuration
     *
     * @see LoadingConfiguration#newBuilder()
     */
    LoadingConfigurationBuilder() {
        translatorCfg = URITranslatorConfiguration.byDefault();
        dereferencing = Dereferencing.CANONICAL;
        preloadedSchemas = Maps.newHashMap();
        for (final SchemaVersion version : SchemaVersion.values())
            preloadedSchemas.put(version.getLocation(), version.getSchema());
        parserFeatures = EnumSet.copyOf(DEFAULT_PARSER_FEATURES);
    }

    /**
     * Build a mutable loading configuration out of a frozen one
     *
     * @param cfg the frozen configuration
     * @see LoadingConfiguration#thaw()
     */
    LoadingConfigurationBuilder(final LoadingConfiguration cfg) {
        downloaders.putAll(cfg.downloaders);
        translatorCfg = cfg.translatorCfg;
        dereferencing = cfg.dereferencing;
        preloadedSchemas = Maps.newHashMap(cfg.preloadedSchemas);
        parserFeatures = EnumSet.copyOf(cfg.parserFeatures);
        enableCache = cfg.enableCache;
    }

    /**
     * Should we enable caching of downloaded schemas
     *
     * <p>Note that this does <b>not</b> affect preloaded schemas</p>
     * 
     * @param enableCache if loaded schemas have to be cached
     * @return this
     */
    public LoadingConfigurationBuilder setEnableCache(final boolean enableCache) {
        this.enableCache = enableCache;
        return this;
    }

    /**
     * Add a new URI downloader
     *
     * @param scheme the scheme
     * @param downloader the downloader
     * @return this
     * @throws NullPointerException scheme or downloader is null
     * @throws IllegalArgumentException illegal scheme
     */
    public LoadingConfigurationBuilder addScheme(final String scheme, final URIDownloader downloader) {
        downloaders.put(scheme, downloader);
        return this;
    }

    /**
     * Remove a downloader for a given scheme
     *
     * @param scheme the scheme
     * @return this
     */
    public LoadingConfigurationBuilder removeScheme(final String scheme) {
        /*
         * No checks for null or anything there: adding entries will have been
         * filtered out anyway, so no harm.
         */
        downloaders.remove(scheme);
        return this;
    }

    public LoadingConfigurationBuilder setURITranslatorConfiguration(
            final URITranslatorConfiguration translatorCfg) {
        this.translatorCfg = translatorCfg;
        return this;
    }

    /**
     * Set the dereferencing mode for this loading configuration
     *
     * <p>By default, it is {@link Dereferencing#CANONICAL}.</p>
     *
     * @param dereferencing the dereferencing mode
     * @return this
     * @throws NullPointerException dereferencing mode is null
     */
    public LoadingConfigurationBuilder dereferencing(final Dereferencing dereferencing) {
        BUNDLE.checkNotNull(dereferencing, "loadingCfg.nullDereferencingMode");
        this.dereferencing = dereferencing;
        return this;
    }

    /**
     * Preload a schema at a given URI
     *
     * <p>Use this if the schema you wish to preload does not have an absolute
     * {@code id} at the top level.</p>
     *
     * <p>Note that the syntax of the schema is not checked at this stage.</p>
     *
     * @param uri the URI to use
     * @param schema the schema
     * @return this
     * @throws NullPointerException the URI or schema is null
     * @throws IllegalArgumentException a schema already exists at this URI
     * @see JsonRef
     */
    public LoadingConfigurationBuilder preloadSchema(final String uri, final JsonNode schema) {
        BUNDLE.checkNotNull(schema, "loadingCfg.nullSchema");
        final URI key = getLocator(uri);
        BUNDLE.checkArgumentPrintf(preloadedSchemas.put(key, schema) == null, "loadingCfg.duplicateURI", key);
        return this;
    }

    /**
     * Preload a schema
     *
     * <p>Use this if the schema already has an absolute {@code id}.</p>
     *
     * @param schema the schema
     * @return this
     * @throws NullPointerException schema is null
     * @throws IllegalArgumentException schema has no {@code id}, or its {@code
     * id} is not an absolute JSON Reference
     * @see JsonRef
     */
    public LoadingConfigurationBuilder preloadSchema(final JsonNode schema) {
        final JsonNode node = schema.path("id");
        BUNDLE.checkArgument(node.isTextual(), "loadingCfg.noIDInSchema");
        return preloadSchema(node.textValue(), schema);
    }

    /**
     * Add a JsonParser feature
     *
     * <p>Use this option to enable non-standard JSON schema source including
     * comments, single quotes, unquoted field names, etc.</p>
     *
     * @param feature the JsonParser feature to enable
     * @throws NullPointerException feature is null
     * @return this
     * @see Feature
     */
    public LoadingConfigurationBuilder addParserFeature(final JsonParser.Feature feature) {
        BUNDLE.checkNotNull(feature, "loadingCfg.nullJsonParserFeature");
        parserFeatures.add(feature);
        return this;
    }

    /**
     * Remove a JSON parser feature
     *
     * <p>Note that attempts to remove {@link Feature#AUTO_CLOSE_SOURCE} will
     * be ignored for safety reasons.</p>
     *
     * @param feature the feature to remove
     * @throws NullPointerException feature is null
     * @return this
     * @see #addParserFeature(JsonParser.Feature)
     */
    public LoadingConfigurationBuilder removeParserFeature(final JsonParser.Feature feature) {
        BUNDLE.checkNotNull(feature, "loadingCfg.nullJsonParserFeature");
        if (feature != JsonParser.Feature.AUTO_CLOSE_SOURCE)
            parserFeatures.remove(feature);
        return this;
    }

    /**
     * Freeze this configuration
     *
     * @return a frozen copy of this builder
     */
    @Override
    public LoadingConfiguration freeze() {
        return new LoadingConfiguration(this);
    }

    private static URI getLocator(final String input) {
        final JsonRef ref;
        try {
            ref = JsonRef.fromString(input);
        } catch (JsonReferenceException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
        BUNDLE.checkArgumentPrintf(ref.isAbsolute(), "jsonRef.notAbsolute", ref);
        return ref.getLocator();
    }
}