Skip to content
Permalink
Browse files

chore: update json-schema-validator to version 1.0.6

This should allow us to use a mappings between public URLs and local copies ala XML catalogs to avoid network calls while validating JSON schema.
  • Loading branch information...
rhwood committed Apr 22, 2019
1 parent 7e78df0 commit 7a2f39c8e6af4ad7500c25a505599027a3653775
@@ -89,7 +89,7 @@
<factorypathentry kind="VARJAR" id="M2_REPO/com/github/purejavacomm/purejavacomm/1.0.1.RELEASE/purejavacomm-1.0.1.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/netbeans/api/org-openide-util-lookup/RELEASE82/org-openide-util-lookup-RELEASE82.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/hid4java/hid4java/0.5.0/hid4java-0.5.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/networknt/json-schema-validator/1.0.4/json-schema-validator-1.0.4.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/networknt/json-schema-validator/1.0.6/json-schema-validator-1.0.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/eclipse/paho/mqtt-client/0.4.0/mqtt-client-0.4.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/alexandriasoftware/swing/jsplitbutton/1.3.1/jsplitbutton-1.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/net/coobird/thumbnailator/0.4.8/thumbnailator-0.4.8.jar" enabled="true" runInBatchMode="false"/>
@@ -222,7 +222,7 @@
<pathelement location="${libdir}/usb4java-javax-1.2.0.jar"/>
<pathelement location="${libdir}/hid4java-0.5.0.jar"/>
<pathelement location="${libdir}/mqtt-client-0.4.0.jar"/>
<pathelement location="${libdir}/json-schema-validator-1.0.4.jar"/>
<pathelement location="${libdir}/json-schema-validator-1.0.6.jar"/>
<pathelement location="${libdir}/jsplitbutton-1.3.1.jar"/>
<pathelement location="${libdir}/thumbnailator-0.4.8.jar"/>
</path>
@@ -0,0 +1,6 @@
[
{
"publicURL": "http://json-schema.org/draft-04/schema#",
"localURL": "classpath:jmri/server/json/schema/json-schema.draftv4.json"
}
]
@@ -54,7 +54,8 @@ public JsonNode doGet(String type, String name, JsonNode data, Locale locale) th
try {
ArrayNode schemas = this.mapper.createArrayNode();
Set<JsonNode> dedup = new HashSet<>();
for (JsonHttpService service : InstanceManager.getDefault(JsonSchemaServiceCache.class).getServices(name)) {
for (JsonHttpService service : InstanceManager.getDefault(JsonSchemaServiceCache.class)
.getServices(name)) {
// separate try/catch blocks to ensure one failure does not
// block following from being accepted
if (server == null || server) {
@@ -90,7 +91,8 @@ public JsonNode doGet(String type, String name, JsonNode data, Locale locale) th
}
return schemas;
} catch (NullPointerException ex) {
throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, Bundle.getMessage(locale, "ErrorUnknownType", name), ex);
throw new JsonException(HttpServletResponse.SC_BAD_REQUEST,
Bundle.getMessage(locale, "ErrorUnknownType", name), ex);
}
}
case JSON.TYPE:
@@ -99,20 +101,25 @@ public JsonNode doGet(String type, String name, JsonNode data, Locale locale) th
root.put(JSON.TYPE, JSON.TYPE);
ObjectNode payload = root.putObject(JSON.DATA);
payload.put(JSON.NAME, name);
payload.put(JSON.SERVER, InstanceManager.getDefault(JsonSchemaServiceCache.class).getServerTypes().contains(name));
payload.put(JSON.CLIENT, InstanceManager.getDefault(JsonSchemaServiceCache.class).getClientTypes().contains(name));
payload.put(JSON.SERVER,
InstanceManager.getDefault(JsonSchemaServiceCache.class).getServerTypes().contains(name));
payload.put(JSON.CLIENT,
InstanceManager.getDefault(JsonSchemaServiceCache.class).getClientTypes().contains(name));
return root;
} else {
throw new JsonException(HttpServletResponse.SC_NOT_FOUND, Bundle.getMessage(locale, "ErrorNotFound", type, name));
throw new JsonException(HttpServletResponse.SC_NOT_FOUND,
Bundle.getMessage(locale, "ErrorNotFound", type, name));
}
default:
throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, Bundle.getMessage(locale, "ErrorUnknownType", type));
throw new JsonException(HttpServletResponse.SC_BAD_REQUEST,
Bundle.getMessage(locale, "ErrorUnknownType", type));
}
}

@Override
public JsonNode doPost(String type, String name, JsonNode data, Locale locale) throws JsonException {
return this.doGet(type, name, data, locale);
throw new JsonException(HttpServletResponse.SC_METHOD_NOT_ALLOWED,
Bundle.getMessage(locale, "PostNotAllowed", type));
}

@Override
@@ -122,11 +129,12 @@ public ArrayNode doGetList(String type, JsonNode parameters, Locale locale) thro
ArrayNode root = this.mapper.createArrayNode();
JsonNode data = this.mapper.createObjectNode();
for (String name : InstanceManager.getDefault(JsonSchemaServiceCache.class).getTypes()) {
root.add(this.doPost(type, name, data, locale));
root.add(this.doGet(type, name, data, locale));
}
return root;
default:
throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, Bundle.getMessage(locale, "UnlistableService", type));
throw new JsonException(HttpServletResponse.SC_BAD_REQUEST,
Bundle.getMessage(locale, "UnlistableService", type));
}
}

@@ -141,7 +149,8 @@ public JsonNode doSchema(String type, boolean server, Locale locale) throws Json
"jmri/server/json/schema/" + type + "-server.json",
"jmri/server/json/schema/" + type + "-client.json");
default:
throw new JsonException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, Bundle.getMessage(locale, "ErrorUnknownType", type));
throw new JsonException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
Bundle.getMessage(locale, "ErrorUnknownType", type));
}
}
}
@@ -4,11 +4,17 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.SchemaValidatorsConfig;
import com.networknt.schema.ValidationMessage;
import com.networknt.schema.url.URLFactory;

import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import javax.annotation.Nonnull;
@@ -26,13 +32,28 @@
*/
public class JsonSchemaServiceCache implements InstanceManagerAutoDefault {

private HashMap<String, Set<JsonHttpService>> services = null;
private Map<String, Set<JsonHttpService>> services = null;
private SchemaValidatorsConfig config = new SchemaValidatorsConfig();
private final Set<String> clientTypes = new HashSet<>();
private final Set<String> serverTypes = new HashSet<>();
private final HashMap<String, JsonSchema> clientSchemas = new HashMap<>();
private final HashMap<String, JsonSchema> serverSchemas = new HashMap<>();
private final Map<String, JsonSchema> clientSchemas = new HashMap<>();
private final Map<String, JsonSchema> serverSchemas = new HashMap<>();
private final ObjectMapper mapper = new ObjectMapper();

public JsonSchemaServiceCache() {
Map<URL, URL> map = new HashMap<>();
try {
for (JsonNode mapping : mapper
.readTree(URLFactory.toURL("resource:jmri/server/json/schema-map.json"))) {
map.put(URLFactory.toURL(mapping.get("publicURL").asText()),
URLFactory.toURL(mapping.get("localURL").asText()));
}
} catch (IOException ex) {
log.error("Unable to read JMRI resources for JSON schema mapping", ex);
}
config.setUrlMappings(map);
}

@Nonnull
public synchronized Set<JsonHttpService> getServices(@Nonnull String type) {
this.cacheServices();
@@ -79,13 +100,13 @@
* Get the client schema for JSON messages or for specific JSON data schema.
*
* @param type the type; use {@link JSON#JSON} to get the schema for
* messages, or any other value for a data schema
* messages, or any other value for a data schema
* @param locale the locale for error messages, if any
* @return the requested schema
* @throws JsonException if unable to get schema due to errors
* processing schema
* processing schema
* @throws IllegalArgumentException if no JSON service provides schemas for
* type
* type
*/
@Nonnull
public JsonSchema getClientSchema(@Nonnull String type, @Nonnull Locale locale) throws JsonException {
@@ -96,33 +117,37 @@ public JsonSchema getClientSchema(@Nonnull String type, @Nonnull Locale locale)
* Get the server schema for JSON messages or for specific JSON data schema.
*
* @param type the type; use {@link JSON#JSON} to get the schema for
* messages, or any other value for a data schema
* messages, or any other value for a data schema
* @param locale the locale for error messages, if any
* @return the requested schema
* @throws JsonException if unable to get schema due to errors
* processing schema
* processing schema
* @throws IllegalArgumentException if no JSON service provides schemas for
* type
* type
*/
@Nonnull
public JsonSchema getServerSchema(@Nonnull String type, @Nonnull Locale locale) throws JsonException {
return this.getSchema(type, true, locale, this.serverSchemas);
}

private synchronized JsonSchema getSchema(@Nonnull String type, boolean server, @Nonnull Locale locale, @Nonnull HashMap<String, JsonSchema> map) throws JsonException {
private synchronized JsonSchema getSchema(@Nonnull String type, boolean server, @Nonnull Locale locale,
@Nonnull Map<String, JsonSchema> map) throws JsonException {
this.cacheServices();
JsonSchema result = map.get(type);
if (result == null) {
for (JsonHttpService service : this.getServices(type)) {
log.debug("Processing {} with {}", type, service);
result = JsonSchemaFactory.getInstance().getSchema(service.doSchema(type, server, locale).path(JSON.DATA).path(JSON.SCHEMA));
System.out.println(config.getUrlMappings());
result = JsonSchemaFactory.getInstance()
.getSchema(service.doSchema(type, server, locale).path(JSON.DATA).path(JSON.SCHEMA), config);
if (result != null) {
map.put(type, result);
break;
}
}
if (result == null) {
throw new IllegalArgumentException("type \"" + type + "\" is not a valid JSON " + (server ? "server" : "client") + " type");
throw new IllegalArgumentException(
"type \"" + type + "\" is not a valid JSON " + (server ? "server" : "client") + " type");
}
}
return result;
@@ -134,12 +159,13 @@ private synchronized JsonSchema getSchema(@Nonnull String type, boolean server,
* @param message the message to validate
* @param server true if message is from the JSON server; false otherwise
* @param locale the locale for any exceptions that need to be reported to
* clients
* clients
* @throws JsonException if the message does not validate
*/
public void validateMessage(@Nonnull JsonNode message, boolean server, @Nonnull Locale locale) throws JsonException {
public void validateMessage(@Nonnull JsonNode message, boolean server, @Nonnull Locale locale)
throws JsonException {
log.trace("validateMessage(\"{}\", \"{}\", \"{}\", ...)", message, server, locale);
HashMap<String, JsonSchema> map = server ? this.serverSchemas : this.clientSchemas;
Map<String, JsonSchema> map = server ? this.serverSchemas : this.clientSchemas;
this.validateJsonNode(message, JSON.JSON, server, locale, map);
if (message.isArray()) {
Iterator<JsonNode> elements = message.elements();
@@ -155,7 +181,8 @@ public void validateMessage(@Nonnull JsonNode message, boolean server, @Nonnull
}
}

private void validateJsonNode(@Nonnull JsonNode node, @Nonnull String type, boolean server, @Nonnull Locale locale, @Nonnull HashMap<String, JsonSchema> map) throws JsonException {
private void validateJsonNode(@Nonnull JsonNode node, @Nonnull String type, boolean server, @Nonnull Locale locale,
@Nonnull Map<String, JsonSchema> map) throws JsonException {
log.trace("validateJsonNode(\"{}\", \"{}\", \"{}\", ...)", node, type, server);
Set<ValidationMessage> errors = null;
try {
@@ -166,7 +193,8 @@ private void validateJsonNode(@Nonnull JsonNode node, @Nonnull String type, bool
if (errors != null && !errors.isEmpty()) {
log.warn("Errors validating {}", node);
errors.forEach((error) -> {
log.warn("JSON Validation Error: {}\n\t{}\n\t{}\n\t{}", error.getCode(), error.getMessage(), error.getPath(), error.getType());
log.warn("JSON Validation Error: {}\n\t{}\n\t{}\n\t{}", error.getCode(), error.getMessage(),
error.getPath(), error.getType());
});
throw new JsonException(server ? 500 : 400, Bundle.getMessage(locale, "LoggedError"));
}
@@ -208,5 +236,6 @@ private void cacheServices() {
}
}
}

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(JsonSchemaServiceCache.class);
}
@@ -31,7 +31,7 @@ public void onMessage(String type, JsonNode data, String method, Locale locale)
case JSON.PUT:
throw new JsonException(HttpServletResponse.SC_METHOD_NOT_ALLOWED, Bundle.getMessage(locale, "PutNotAllowed", type));
case JSON.GET:
this.connection.sendMessage(this.service.doPost(type, data.path(JSON.NAME).asText(JSON.JSON), data, locale));
this.connection.sendMessage(this.service.doGet(type, data.path(JSON.NAME).asText(JSON.JSON), data, locale));
break;
default:
throw new JsonException(HttpServletResponse.SC_METHOD_NOT_ALLOWED, Bundle.getMessage(locale, "MethodNotImplemented", method, type));

0 comments on commit 7a2f39c

Please sign in to comment.
You can’t perform that action at this time.