package de.galan.verjson.step.validation; import static org.apache.commons.lang3.StringUtils.*; import java.io.IOException; import java.util.List; import com.fasterxml.jackson.databind.JsonNode; import com.github.fge.jackson.JsonLoader; import com.github.fge.jsonschema.core.exceptions.ProcessingException; import com.github.fge.jsonschema.core.report.ProcessingMessage; import com.github.fge.jsonschema.core.report.ProcessingReport; import com.github.fge.jsonschema.main.JsonSchema; import com.github.fge.jsonschema.main.JsonSchemaFactory; import com.google.common.base.StandardSystemProperty; import com.google.common.collect.Lists; import de.galan.verjson.step.ProcessStepException; import de.galan.verjson.step.Step; import de.galan.verjson.util.MetaWrapper; /** * Creates a JSON Schema Validator to check json against it, using https://github.com/fge/json-schema-validator * * @author daniel */ public class Validation implements Step { protected final static String LS = StandardSystemProperty.LINE_SEPARATOR.value(); String description; JsonSchema schema; // thread-safe static JsonSchemaFactory factory; // cached public Validation(String schema) { this(schema, null); } public Validation(String schema, String description) { this.description = description; this.schema = create(schema); } public String getDescription() { return description; } protected String getDescriptionAppendable() { return isBlank(getDescription()) ? EMPTY : (" (" + getDescription() + ")"); } protected static synchronized JsonSchemaFactory getFactory() { if (factory == null) { factory = JsonSchemaFactory.byDefault(); } return factory; } protected JsonSchemaFactory getJsonSchemaFactory() { return getFactory(); } @Override public void process(JsonNode node) throws ProcessStepException { validate(MetaWrapper.getData(node)); } protected JsonSchema getSchema() { return schema; } public void validate(JsonNode node) throws InvalidJsonException { ProcessingReport report = null; try { report = getSchema().validate(node); } catch (Throwable ex) { throw new InvalidJsonException("Could not validate JSON against schema" + getDescriptionAppendable(), ex); } if (!report.isSuccess()) { StringBuilder builder = new StringBuilder(); builder.append("Could not validate JSON against schema"); builder.append(getDescriptionAppendable()); builder.append(":"); builder.append(LS); List<ProcessingMessage> messages = Lists.newArrayList(report); for (int i = 0; i < messages.size(); i++) { builder.append("- "); builder.append(messages.get(i).getMessage()); builder.append(i == (messages.size() - 1) ? EMPTY : LS); } throw new InvalidJsonException(builder.toString()); } } public JsonSchema create(String schemaString) { JsonSchema jsonSchema = null; try { JsonNode schemaNode = JsonLoader.fromString(schemaString); if (!getJsonSchemaFactory().getSyntaxValidator().schemaIsValid(schemaNode)) { throw new InvalidSchemaException("JSON Schema is invalid" + getDescriptionAppendable()); } jsonSchema = getJsonSchemaFactory().getJsonSchema(schemaNode); } catch (NullPointerException | IOException | ProcessingException ex) { throw new InvalidSchemaException("JSON Schema could not be loaded" + getDescriptionAppendable(), ex); } return jsonSchema; } }