Skip to content

Commit

Permalink
CAMEL-9799: Switched to use ResourceEndpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ullgren committed Oct 6, 2017
1 parent 7d85a4b commit 2712739
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 332 deletions.
@@ -1,9 +1,7 @@
== JSON Schema Validator Component
=== Everit Json Schema Validator Component
*Available as of Camel version *


*Available as of Camel version 2.20*
*Available as of Camel version 2.21*

The JSON Schema Validator component performs bean validation of the message body
agains JSON Schemas using the Everit.org JSON Schema library
Expand Down Expand Up @@ -57,14 +55,15 @@ with the following path and query parameters:
[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *resourceUri* | *Required* URL to a local resource on the classpath or a reference to lookup a bean in the Registry or a full URL to a remote resource or resource on the file system which contains the JSON Schema to validate against. | | String
| *resourceUri* | *Required* Path to the resource. You can prefix with: classpath file http ref or bean. classpath file and http loads the resource using these protocols (classpath is default). ref will lookup the resource in the registry. bean will call a method on a bean to be used as the resource. For bean you can specify the method name after dot eg bean:myBean.myMethod. | | String
|===

==== Query Parameters (6 parameters):
==== Query Parameters (7 parameters):

[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *contentCache* (producer) | Sets whether to use resource content cache or not | false | boolean
| *failOnNullBody* (producer) | Whether to fail if no body exists. | true | boolean
| *failOnNullHeader* (producer) | Whether to fail if no header exists when validating against a header. | true | boolean
| *headerName* (producer) | To validate against a header instead of the message body. | | String
Expand Down
Expand Up @@ -20,7 +20,6 @@
import java.io.InputStream;

import org.apache.camel.CamelContext;
import org.apache.camel.util.ResourceHelper;
import org.everit.json.schema.Schema;
import org.everit.json.schema.loader.SchemaLoader;
import org.everit.json.schema.loader.SchemaLoader.SchemaLoaderBuilder;
Expand All @@ -32,11 +31,11 @@ public class DefaultJsonSchemaLoader implements
JsonSchemaLoader {

@Override
public Schema createSchema(CamelContext camelContext, String resourceUri) throws IOException {
public Schema createSchema(CamelContext camelContext, InputStream schemaInputStream) throws IOException {

SchemaLoaderBuilder schemaLoaderBuilder = SchemaLoader.builder().draftV6Support();

try (InputStream inputStream = ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, resourceUri)) {
try (InputStream inputStream = schemaInputStream) {
JSONObject rawSchema = new JSONObject(new JSONTokener(inputStream));
return schemaLoaderBuilder.schemaJson(rawSchema).build().load().build();
}
Expand Down
Expand Up @@ -16,13 +16,29 @@
*/
package org.apache.camel.component.everit.jsonschema;

import java.io.IOException;
import java.io.InputStream;

import org.apache.camel.CamelContext;
import org.everit.json.schema.FormatValidator;
import org.everit.json.schema.Schema;

/**
* Can be used to create custom schema for the JSON validator endpoint.
* This interface is useful to add custom {@link FormatValidator} to the {@link Schema}
*
* For more information see
* <a href="https://github.com/everit-org/json-schema#format-validators">Format Validators</a>
* in the Everit JSON Schema documentation.
*/
public interface JsonSchemaLoader {

Schema createSchema(CamelContext camelContext, String resourceUri) throws IOException;
/**
* Create a new Schema based on the schema input stream.
* @param camelContext camel context
* @param schemaInputStream the resource input stream
* @return a Schema to be used when validating incoming requests
* @throws Exception if
*/
Schema createSchema(CamelContext camelContext, InputStream schemaInputStream) throws Exception;

}

This file was deleted.

Expand Up @@ -16,30 +16,37 @@
*/
package org.apache.camel.component.everit.jsonschema;

import java.io.IOException;
import java.io.InputStream;

import org.apache.camel.Component;
import org.apache.camel.Consumer;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.api.management.ManagedOperation;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.impl.DefaultEndpoint;
import org.apache.camel.spi.Metadata;
import org.apache.camel.component.ResourceEndpoint;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriPath;
import org.apache.camel.util.IOHelper;
import org.everit.json.schema.ObjectSchema;
import org.everit.json.schema.Schema;
import org.everit.json.schema.ValidationException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* Validates the payload of a message using XML Schema and JAXP Validation.
*/
@ManagedResource(description = "Managed JSON ValidatorEndpoint")
@UriEndpoint(scheme = "json-validator", title = "JSON Schema Validator", syntax = "json-validator:resourceUri", producerOnly = true, label = "core,validation")
public class JsonSchemaValidatorEndpoint extends DefaultEndpoint {
public class JsonSchemaValidatorEndpoint extends ResourceEndpoint {

@UriPath(description = "URL to a local resource on the classpath, or a reference to lookup a bean in the Registry,"
+ " or a full URL to a remote resource or resource on the file system which contains the JSON Schema to validate against.")
@Metadata(required = "true")
private String resourceUri;
private static final Logger LOG = LoggerFactory.getLogger(JsonSchemaValidatorEndpoint.class);

@UriParam(label = "advanced", description = "To use a custom org.apache.camel.component.everit.jsonschema.JsonValidatorErrorHandler. "
+ "The default error handler captures the errors and throws an exception.")
private JsonValidatorErrorHandler errorHandler = new DefaultJsonValidationErrorHandler();
Expand All @@ -52,68 +59,93 @@ public class JsonSchemaValidatorEndpoint extends DefaultEndpoint {
@UriParam(description = "To validate against a header instead of the message body.")
private String headerName;


/**
* We need a one-to-one relation between endpoint and a JsonSchemaReader
* to be able to clear the cached schema. See method
* {@link #clearCachedSchema}.
*/
private JsonSchemaReader schemaReader;

private Schema schema;

public JsonSchemaValidatorEndpoint(String endpointUri, Component component, String resourceUri) {
super(endpointUri, component);
this.resourceUri = resourceUri;
super(endpointUri, component, resourceUri);
}

@Override
public void clearContentCache() {
this.schema = null;
super.clearContentCache();
}

@ManagedOperation(description = "Clears the cached schema, forcing to re-load the schema on next request")
public void clearCachedSchema() {
this.schemaReader.setSchema(null); // will cause to reload the schema
@Override
public ExchangePattern getExchangePattern() {
return ExchangePattern.InOut;
}

@Override
public Producer createProducer() throws Exception {
if (this.schemaReader == null) {
this.schemaReader = new JsonSchemaReader(getCamelContext(), resourceUri, schemaLoader);
// Load the schema once when creating the producer to fail fast if the schema is invalid.
this.schemaReader.getSchema();
protected void onExchange(Exchange exchange) throws Exception {
Object jsonPayload = null;
InputStream is = null;
// Get a local copy of the current schema to improve concurrency.
Schema localSchema = this.schema;
if (localSchema == null) {
localSchema = getOrCreateSchema();
}
try {
is = getContentToValidate(exchange, InputStream.class);
if (shouldUseHeader()) {
if (is == null && isFailOnNullHeader()) {
throw new NoJsonHeaderValidationException(exchange, headerName);
}
} else {
if (is == null && isFailOnNullBody()) {
throw new NoJsonBodyValidationException(exchange);
}
}
if (is != null) {
if (schema instanceof ObjectSchema) {
jsonPayload = new JSONObject(new JSONTokener(is));
} else {
jsonPayload = new JSONArray(new JSONTokener(is));
}
// throws a ValidationException if this object is invalid
schema.validate(jsonPayload);
LOG.debug("JSON is valid");
}
} catch (ValidationException e) {
this.errorHandler.handleErrors(exchange, schema, e);
} catch (JSONException e) {
this.errorHandler.handleErrors(exchange, schema, e);
} finally {
IOHelper.close(is);
}
JsonValidatingProcessor validator = new JsonValidatingProcessor(this.schemaReader);
configureValidator(validator);

return new JsonSchemaValidatorProducer(this, validator);
}

private void configureValidator(JsonValidatingProcessor validator) {
validator.setErrorHandler(errorHandler);
validator.setFailOnNullBody(failOnNullBody);
validator.setFailOnNullHeader(failOnNullHeader);
validator.setHeaderName(headerName);
}

@Override
public Consumer createConsumer(Processor processor) throws Exception {
throw new UnsupportedOperationException("Cannot consume from validator");

private <T> T getContentToValidate(Exchange exchange, Class<T> clazz) {
if (shouldUseHeader()) {
return exchange.getIn().getHeader(headerName, clazz);
} else {
return exchange.getIn().getBody(clazz);
}
}

@Override
public boolean isSingleton() {
return true;
private boolean shouldUseHeader() {
return headerName != null;
}


public String getResourceUri() {
return resourceUri;
}

/**
* URL to a local resource on the classpath, or a reference to lookup a bean in the Registry,
* or a full URL to a remote resource or resource on the file system which contains the JSON Schema to validate against.
* Synchronized method to create a schema if is does not already exist.
*
* @return The currently loaded schema
* @throws IOException
*/
public void setResourceUri(String resourceUri) {
this.resourceUri = resourceUri;
private Schema getOrCreateSchema() throws Exception {
synchronized (this) {
if (this.schema == null) {
this.schema = this.schemaLoader.createSchema(getCamelContext(), this.getResourceAsInputStream());
}
}
return this.schema;
}

@Override
protected String createEndpointUri() {
return "json-validator:" + getResourceUri();
}

public JsonValidatorErrorHandler getErrorHandler() {
return errorHandler;
Expand Down

This file was deleted.

0 comments on commit 2712739

Please sign in to comment.