All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.fge.jsonschema.syntax.hyperschema.draftv3.LinksSyntaxChecker Maven / Gradle / Ivy

There is a newer version: 2.2.6
Show newest version
/*
 * Copyright (c) 2012, Francis Galiegue 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Lesser GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Lesser GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */

package com.github.fge.jsonschema.syntax.hyperschema.draftv3;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.net.MediaType;
import com.github.fge.jsonschema.report.Message;
import com.github.fge.jsonschema.syntax.AbstractSyntaxChecker;
import com.github.fge.jsonschema.syntax.SyntaxChecker;
import com.github.fge.jsonschema.syntax.SyntaxValidator;
import com.github.fge.jsonschema.util.CharMatchers;
import com.github.fge.jsonschema.util.NodeType;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.regex.Pattern;

/**
 * Syntax validator for hyper shema's {@code links} keyword
 *
 * 

This keyword is quite the monster, and what is more, the JSON file does * not agree with the spec on all points. It is chosen here to follow the * specification.

*/ public final class LinksSyntaxChecker extends AbstractSyntaxChecker { private static final Set LDO_REQUIRED_MEMBERS = ImmutableSet.of("href", "rel"); // FIXME: does not account for { or } within templates private static final Pattern HREF_TEMPLATE = Pattern.compile("\\{[^{}]*\\}"); private static final SyntaxChecker INSTANCE = new LinksSyntaxChecker(); private LinksSyntaxChecker() { super("links", NodeType.ARRAY); } public static SyntaxChecker getInstance() { return INSTANCE; } @Override public void checkValue(final SyntaxValidator validator, final List messages, final JsonNode schema) { final JsonNode value = schema.get(keyword); final Message.Builder msg = newMsg(); final int size = value.size(); JsonNode ldo; NodeType type; for (int index = 0; index < size; index++) { ldo = value.get(index); type = NodeType.getNodeType(ldo); msg.addInfo("index", index); if (type != NodeType.OBJECT) { msg.addInfo("expected", NodeType.OBJECT).addInfo("found", type) .setMessage("incorrect array element type"); messages.add(msg.build()); continue; } checkLDOSyntax(validator, msg, messages, ldo); } } private static void checkLDOSyntax(final SyntaxValidator validator, final Message.Builder msg, final List messages, final JsonNode ldo) { final Set memberNames = Sets.newHashSet(ldo.fieldNames()); if (!memberNames.containsAll(LDO_REQUIRED_MEMBERS)) { final SortedSet missing = Sets.newTreeSet(LDO_REQUIRED_MEMBERS); missing.removeAll(memberNames); msg.addInfo("required", LDO_REQUIRED_MEMBERS) .addInfo("missing", missing) .setMessage("missing required properties in link description " + "object"); messages.add(msg.build()); return; } /* * Check correctness of the "rel" and "href" members */ checkRelation(msg, messages, ldo); checkHref(msg, messages, ldo); if (ldo.has("targetSchema")) { final JsonNode node = ldo.get("targetSchema"); final NodeType type = NodeType.getNodeType(node); if (type != NodeType.OBJECT) { msg.setMessage("incorrect type for targetSchema member") .addInfo("expected", NodeType.OBJECT) .addInfo("found", type); messages.add(msg.build()); } else validator.validate(messages, node); } /* * Check submission links properties (section 6.1.1.4 of the draft) */ checkSubmissionLink(msg, messages, ldo); } private static void checkRelation(final Message.Builder msg, final List messages, final JsonNode ldo) { /* * FIXME: whether it describes a real relation is actually not checked. * * We check that the syntax of the relation matches the "reg-rel-type" * grammar token defined in RFC 5988, section 5. */ final JsonNode relNode = ldo.get("rel"); final NodeType type = NodeType.getNodeType(relNode); if (type != NodeType.STRING) { msg.setMessage("wrong node type for \"rel\" member") .addInfo("expected", NodeType.STRING).addInfo("found", type); messages.add(msg.build()); return; } final String relation = relNode.textValue(); if (relation.isEmpty()) { msg.setMessage("\"rel\" member value must not be empty"); messages.add(msg.build()); return; } if (!CharMatchers.LOALPHA.matches(relation.charAt(0))) { msg.setMessage("illegal \"rel\" member value: must start with a " + "lowercase ASCII letter"); messages.add(msg.build()); return; } if (!CharMatchers.REL_TOKEN.matchesAllOf(relation.substring(1))) { msg.setMessage("illegal token in \"rel\" member value"); messages.add(msg.build()); } } private static void checkHref(final Message.Builder msg, final List messages, final JsonNode ldo) { final JsonNode hrefNode = ldo.get("href"); final NodeType type = NodeType.getNodeType(hrefNode); if (type != NodeType.STRING) { msg.setMessage("wrong node type for \"href\" member") .addInfo("expected", NodeType.STRING).addInfo("found", type); messages.add(msg.build()); return; } // We must expand templates with a value which is valid in all places // of a URI. ASCII lowercase letters are always valid, use that. final String template = hrefNode.textValue(); final String uri = HREF_TEMPLATE.matcher(template).replaceAll("foo"); try { new URI(uri); } catch (URISyntaxException ignored) { msg.setMessage("expanded href value is not a URI") .addInfo("template", template); messages.add(msg.build()); } } private static void checkSubmissionLink(final Message.Builder msg, final List messages, final JsonNode ldo) { /* * This is quite messy: in the hyper-schema document, there is no * "schema", however, in the draft text, there is... Stick to the draft. * * And there is also "targetSchema" along with "schema"... Gee. */ NodeType type; if (ldo.has("schema")) { type = NodeType.getNodeType(ldo.get("schema")); if (type != NodeType.OBJECT) { msg.setMessage("incorrect type for schema member") .addInfo("expected", NodeType.OBJECT) .addInfo("found", type); messages.add(msg.build()); } } if (!ldo.has("enctype")) // Nothing to do return; if (!ldo.has("method")) { msg.setMessage("enctype must be paired with method"); messages.add(msg.build()); return; } JsonNode node; /* * Check enctype */ node = ldo.get("enctype"); type = NodeType.getNodeType(node); if (type != NodeType.STRING) { msg.setMessage("incorrect type for enctype").addInfo("found", type) .addInfo("expected", NodeType.STRING); messages.add(msg.build()); } else try { MediaType.parse(node.textValue()); } catch (IllegalArgumentException ignored) { msg.setMessage("enctype is not a valid media type") .addInfo("value", node); messages.add(msg.build()); } /* * Check method */ node = ldo.get("method"); type = NodeType.getNodeType(node); if (type != NodeType.STRING) { msg.setMessage("incorrect type for method").addInfo("found", type) .addInfo("expected", NodeType.STRING); messages.add(msg.build()); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy