Search in sources :

Example 1 with SchemaResourceResolver

use of org.apache.synapse.util.jaxp.SchemaResourceResolver in project wso2-synapse by wso2.

the class ValidateMediator method mediate.

@SuppressWarnings({ "ThrowableResultOfMethodCallIgnored" })
public boolean mediate(MessageContext synCtx) {
    // This is the actual schema instance used to create a new schema
    Schema cachedSchema = null;
    JsonSchema cachedJsonSchema = null;
    if (synCtx.getEnvironment().isDebuggerEnabled()) {
        if (super.divertMediationRoute(synCtx)) {
            return true;
        }
    }
    SynapseLog synLog = getLog(synCtx);
    synLog.traceOrDebug("Start : Validate mediator");
    if (synLog.isTraceTraceEnabled()) {
        synLog.traceTrace("Message : " + synCtx.getEnvelope());
    }
    org.apache.axis2.context.MessageContext a2mc = ((Axis2MessageContext) synCtx).getAxis2MessageContext();
    if (JsonUtil.hasAJsonPayload(a2mc)) {
        ProcessingReport report;
        // This JsonSchema used if user decide not to cache the schema. In such a situation jsonSchema will not used.
        JsonSchema uncachedJsonSchema = null;
        JsonNode uncachedJsonSchemaNode = null;
        // flag to check if we need to initialize/re-initialize the schema
        StringBuilder combinedPropertyKey = new StringBuilder();
        StringBuilder cachedJsonSchemaKey = new StringBuilder();
        // if any of the schemas are not loaded, or have expired, load or re-load them
        boolean reCreate = !cacheSchema || isReCreate(synCtx, combinedPropertyKey);
        /*
             * Check for the cached schema in the map and if it's available get
             * the cached schema else re initialize the schema
             */
        if (cachedJsonSchemaMap.containsKey(combinedPropertyKey.toString())) {
            cachedJsonSchema = cachedJsonSchemaMap.get(combinedPropertyKey.toString());
        } else {
            reCreate = true;
        }
        // do not re-initialize schema unless required
        synchronized (validatorLock) {
            if (reCreate || cachedJsonSchema == null) {
                Object jsonSchemaObj = null;
                for (Value schemaKey : schemaKeys) {
                    // Derive actual key from message context
                    String propName = schemaKey.evaluateValue(synCtx);
                    jsonSchemaObj = synCtx.getEntry(propName);
                    cachedJsonSchemaKey.append(propName);
                }
                if (jsonSchemaObj == null) {
                    handleException("Can not find JSON Schema " + cachedJsonSchemaKey.toString(), synCtx);
                }
                try {
                    if (jsonSchemaObj instanceof String) {
                        if (cacheSchema) {
                            jsonSchemaNode = JsonLoader.fromString((String) jsonSchemaObj);
                        } else {
                            uncachedJsonSchemaNode = JsonLoader.fromString((String) jsonSchemaObj);
                        }
                    } else if (jsonSchemaObj instanceof OMTextImpl) {
                        // if Schema provides from registry
                        InputStreamReader reader = null;
                        try {
                            reader = new InputStreamReader(((OMTextImpl) jsonSchemaObj).getInputStream());
                            if (cacheSchema) {
                                jsonSchemaNode = JsonLoader.fromReader(reader);
                            } else {
                                uncachedJsonSchemaNode = JsonLoader.fromReader(reader);
                            }
                        } finally {
                            if (reader != null) {
                                try {
                                    reader.close();
                                } catch (IOException e) {
                                    log.warn("Error while closing registry resource stream. " + e);
                                }
                            }
                        }
                    } else {
                        handleException("Can not find valid JSON Schema content", synCtx);
                    }
                    if (cacheSchema) {
                        cachedJsonSchema = jsonSchemaFactory.getJsonSchema(jsonSchemaNode);
                        /*
                             * Initially adds the cached schema to the map if it's
                             * not available
                             */
                        if (!cachedJsonSchemaMap.containsKey(cachedJsonSchemaKey.toString())) {
                            cachedJsonSchemaMap.put(cachedJsonSchemaKey.toString(), cachedJsonSchema);
                        /*
                             * Removes the existing cached schema and adds the
                             * new cached schema This is used when editing a
                             * registry resource or when the cache expires
                             */
                        } else if (cachedJsonSchemaMap.containsKey(cachedJsonSchemaKey.toString())) {
                            cachedJsonSchemaMap.remove(cachedJsonSchemaKey.toString());
                            cachedJsonSchemaMap.put(cachedJsonSchemaKey.toString(), cachedJsonSchema);
                        }
                    } else {
                        uncachedJsonSchema = jsonSchemaFactory.getJsonSchema(uncachedJsonSchemaNode);
                    }
                } catch (ProcessingException | IOException e) {
                    handleException("Error while validating the JSON Schema", e, synCtx);
                }
            }
        }
        try {
            if (cachedJsonSchema == null && uncachedJsonSchema == null) {
                handleException("Failed to create JSON Schema Validator", synCtx);
            }
            String jsonPayload = null;
            if (sourcePath != null) {
                // evaluating
                if (sourcePath instanceof SynapseJsonPath) {
                    jsonPayload = sourcePath.stringValueOf(synCtx);
                } else {
                    handleException("Could not find the JSONPath evaluator for Source", synCtx);
                }
            } else {
                jsonPayload = JsonUtil.jsonPayloadToString(a2mc);
            }
            if (jsonPayload == null || jsonPayload.length() == 0) {
                // making empty json string
                jsonPayload = "{}";
            }
            if (cacheSchema) {
                report = cachedJsonSchema.validate(JsonLoader.fromString(jsonPayload));
            } else {
                report = uncachedJsonSchema.validate(JsonLoader.fromString(jsonPayload));
            }
            if (report.isSuccess()) {
                return true;
            } else {
                if (synLog.isTraceOrDebugEnabled()) {
                    String msg = "Validation of JSON failed against the given schema(s) " + cachedJsonSchemaKey.toString() + " with error : " + report + " Executing 'on-fail' sequence";
                    synLog.traceOrDebug(msg);
                    // write a warning to the service log
                    synCtx.getServiceLog().warn(msg);
                    if (synLog.isTraceTraceEnabled()) {
                        synLog.traceTrace("Failed message envelope : " + synCtx.getEnvelope());
                    }
                }
                // set error message and detail (stack trace) into the message context
                Iterator<ProcessingMessage> itrErrorMessages = report.iterator();
                // there is only one element in the report
                if (itrErrorMessages.hasNext()) {
                    ProcessingMessage processingMessage = itrErrorMessages.next();
                    String errorMessage = processingMessage.getMessage();
                    synCtx.setProperty(SynapseConstants.ERROR_MESSAGE, errorMessage);
                    synCtx.setProperty(SynapseConstants.ERROR_DETAIL, "Error while validating Json message " + errorMessage);
                }
                // invokes the "on-fail" sequence of mediator
                return invokeOnFailSequence(synCtx);
            }
        } catch (ProcessingException | IOException e) {
            String msg = "";
            if (sourcePath != null) {
                msg = " for JSONPath " + sourcePath.getExpression();
            }
            handleException("Error while validating the JSON Schema" + msg, e, synCtx);
        }
    } else {
        Source validateSrc;
        try {
            // Input source for the validation
            validateSrc = getValidationSource(synCtx, synLog);
        } catch (SynapseException e) {
            /* Catches the exception here to forward to 'on-fail' sequence.
                   The 'on-fail' sequence will get invoked when the given xpath source is not available
                   in the message.
                 */
            String errorMessage = "Error occurred while accessing source element: " + source;
            if (synLog.isTraceOrDebugEnabled()) {
                String msg = "Error occurred while accessing source element : " + source + "with error : '" + e.getMessage() + "'. Executing 'on-fail' sequence";
                synLog.traceOrDebug(msg);
                // write a warning to the service log
                synCtx.getServiceLog().warn(msg);
                if (synLog.isTraceTraceEnabled()) {
                    synLog.traceTrace("Failed message envelope : " + synCtx.getEnvelope());
                }
            }
            synCtx.setProperty(SynapseConstants.ERROR_MESSAGE, errorMessage);
            synCtx.setProperty(SynapseConstants.ERROR_DETAIL, e.getMessage());
            // invokes the "on-fail" sequence of mediator
            return invokeOnFailSequence(synCtx);
        }
        StringBuilder combinedPropertyKey = new StringBuilder();
        // flag to check if we need to initialize/re-initialize the schema
        // if any of the schemas are not loaded, or have expired, load or re-load them
        boolean reCreate = !cacheSchema || isReCreate(synCtx, combinedPropertyKey);
        /*
             * Check for the cached schema in the map and if it's available get
             * the cached schema else re initialize the schema
             */
        if (cachedSchemaMap.containsKey(combinedPropertyKey.toString())) {
            cachedSchema = cachedSchemaMap.get(combinedPropertyKey.toString());
        } else {
            reCreate = true;
        }
        // This is the reference to the DefaultHandler instance
        ValidateMediatorErrorHandler errorHandler = new ValidateMediatorErrorHandler();
        // This instance used to handle schema not cached scenarios.
        Schema uncachedSchema = null;
        // do not re-initialize schema unless required
        synchronized (validatorLock) {
            if (reCreate || cachedSchema == null) {
                factory.setErrorHandler(errorHandler);
                StreamSource[] sources = new StreamSource[schemaKeys.size()];
                StringBuilder cachedSchemaKey = new StringBuilder();
                int i = 0;
                for (Value schemaKey : schemaKeys) {
                    // Derive actual key from message context
                    String propName = schemaKey.evaluateValue(synCtx);
                    Object schemaObject = synCtx.getEntry(propName);
                    if (schemaObject == null) {
                        throw new SynapseException("No Schema is available with the key  : " + propName);
                    }
                    sources[i++] = SynapseConfigUtils.getStreamSource(schemaObject);
                    // Generating a cached schema key
                    cachedSchemaKey.append(propName);
                }
                // load the UserDefined SchemaURIResolver implementations
                try {
                    SynapseConfiguration synCfg = synCtx.getConfiguration();
                    if (synCfg.getProperty(SynapseConstants.SYNAPSE_SCHEMA_RESOLVER) != null) {
                        setUserDefinedSchemaResourceResolver(synCtx);
                    } else {
                        factory.setResourceResolver(new SchemaResourceResolver(synCtx.getConfiguration(), resourceMap));
                    }
                    if (cacheSchema) {
                        cachedSchema = factory.newSchema(sources);
                        /*
                             * Initially adds the cached schema to the map if it's
                             * not available
                             */
                        if (!cachedSchemaMap.containsKey(cachedSchemaKey.toString())) {
                            cachedSchemaMap.put(cachedSchemaKey.toString(), cachedSchema);
                        /*
                             * Removes the existing cached schema and adds the
                             * new cached schema This is used when editing a
                             * registry resource or when the cache expires
                             */
                        } else if (cachedSchemaMap.containsKey(cachedSchemaKey.toString())) {
                            cachedSchemaMap.remove(cachedSchemaKey.toString());
                            cachedSchemaMap.put(cachedSchemaKey.toString(), cachedSchema);
                        }
                    } else {
                        uncachedSchema = factory.newSchema(sources);
                    }
                } catch (SAXException e) {
                    handleException("Error creating a new schema objects for " + "schemas : " + schemaKeys.toString(), e, synCtx);
                } catch (RuntimeException e) {
                    handleException("Error creating a new schema objects for " + "schemas : " + schemaKeys.toString(), e, synCtx);
                }
                if (errorHandler.isValidationError()) {
                    // reset the errorhandler state
                    errorHandler.setValidationError(false);
                    cachedSchema = null;
                    // Removes the erroneous cached schema from the map
                    if (cachedSchemaMap.containsKey(cachedSchemaKey.toString())) {
                        cachedSchemaMap.remove(cachedSchemaKey.toString());
                    }
                    handleException("Error creating a new schema objects for schemas : " + schemaKeys.toString(), errorHandler.getSaxParseException(), synCtx);
                }
            }
        }
        // no need to synchronize, schema instances are thread-safe
        try {
            Validator validator;
            if (cacheSchema) {
                validator = cachedSchema.newValidator();
            } else {
                validator = uncachedSchema.newValidator();
            }
            validator.setErrorHandler(errorHandler);
            // perform actual validation
            validator.validate(validateSrc);
            if (errorHandler.isValidationError()) {
                if (synLog.isTraceOrDebugEnabled()) {
                    String msg = "Validation of element returned by XPath : " + source + " failed against the given schema(s) " + schemaKeys + "with error : " + errorHandler.getSaxParseException().getMessage() + " Executing 'on-fail' sequence";
                    synLog.traceOrDebug(msg);
                    // write a warning to the service log
                    synCtx.getServiceLog().warn(msg);
                    if (synLog.isTraceTraceEnabled()) {
                        synLog.traceTrace("Failed message envelope : " + synCtx.getEnvelope());
                    }
                }
                // set error message and detail (stack trace) into the message context
                synCtx.setProperty(SynapseConstants.ERROR_MESSAGE, errorHandler.getAllExceptions());
                synCtx.setProperty(SynapseConstants.ERROR_EXCEPTION, errorHandler.getSaxParseException());
                synCtx.setProperty(SynapseConstants.ERROR_DETAIL, FaultHandler.getStackTrace(errorHandler.getSaxParseException()));
                // invokes the "on-fail" sequence of the mediator
                return invokeOnFailSequence(synCtx);
            }
        } catch (SAXException e) {
            handleException("Error validating " + source + " element", e, synCtx);
        } catch (IOException e) {
            handleException("Error validating " + source + " element", e, synCtx);
        }
    }
    if (synLog.isTraceOrDebugEnabled()) {
        synLog.traceOrDebug("Validation of element returned by the XPath expression : " + source + " succeeded against the given schemas and the current message");
        synLog.traceOrDebug("End : Validate mediator");
    }
    return true;
}
Also used : SynapseException(org.apache.synapse.SynapseException) Schema(javax.xml.validation.Schema) JsonSchema(com.github.fge.jsonschema.main.JsonSchema) JsonSchema(com.github.fge.jsonschema.main.JsonSchema) JsonNode(com.fasterxml.jackson.databind.JsonNode) SynapseConfiguration(org.apache.synapse.config.SynapseConfiguration) StreamSource(javax.xml.transform.stream.StreamSource) Source(javax.xml.transform.Source) SAXException(org.xml.sax.SAXException) ProcessingReport(com.github.fge.jsonschema.core.report.ProcessingReport) SynapseLog(org.apache.synapse.SynapseLog) Axis2MessageContext(org.apache.synapse.core.axis2.Axis2MessageContext) ProcessingException(com.github.fge.jsonschema.core.exceptions.ProcessingException) InputStreamReader(java.io.InputStreamReader) ProcessingMessage(com.github.fge.jsonschema.core.report.ProcessingMessage) StreamSource(javax.xml.transform.stream.StreamSource) OMTextImpl(org.apache.axiom.om.impl.llom.OMTextImpl) IOException(java.io.IOException) SchemaResourceResolver(org.apache.synapse.util.jaxp.SchemaResourceResolver) SynapseJsonPath(org.apache.synapse.util.xpath.SynapseJsonPath) Value(org.apache.synapse.mediators.Value) Validator(javax.xml.validation.Validator)

Aggregations

JsonNode (com.fasterxml.jackson.databind.JsonNode)1 ProcessingException (com.github.fge.jsonschema.core.exceptions.ProcessingException)1 ProcessingMessage (com.github.fge.jsonschema.core.report.ProcessingMessage)1 ProcessingReport (com.github.fge.jsonschema.core.report.ProcessingReport)1 JsonSchema (com.github.fge.jsonschema.main.JsonSchema)1 IOException (java.io.IOException)1 InputStreamReader (java.io.InputStreamReader)1 Source (javax.xml.transform.Source)1 StreamSource (javax.xml.transform.stream.StreamSource)1 Schema (javax.xml.validation.Schema)1 Validator (javax.xml.validation.Validator)1 OMTextImpl (org.apache.axiom.om.impl.llom.OMTextImpl)1 SynapseException (org.apache.synapse.SynapseException)1 SynapseLog (org.apache.synapse.SynapseLog)1 SynapseConfiguration (org.apache.synapse.config.SynapseConfiguration)1 Axis2MessageContext (org.apache.synapse.core.axis2.Axis2MessageContext)1 Value (org.apache.synapse.mediators.Value)1 SchemaResourceResolver (org.apache.synapse.util.jaxp.SchemaResourceResolver)1 SynapseJsonPath (org.apache.synapse.util.xpath.SynapseJsonPath)1 SAXException (org.xml.sax.SAXException)1