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

net.javacrumbs.springws.test.helper.MessageValidator Maven / Gradle / Ivy

There is a newer version: 0.22
Show newest version
/**
 * Copyright 2009-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.javacrumbs.springws.test.helper;

import java.io.IOException;
import java.util.Map;
import java.util.regex.Pattern;

import net.javacrumbs.springws.test.WsTestException;
import net.javacrumbs.springws.test.common.DefaultMessageComparator;
import net.javacrumbs.springws.test.common.ExpressionEvaluator;
import net.javacrumbs.springws.test.common.MessageComparator;
import net.javacrumbs.springws.test.common.SchemaValidator;
import net.javacrumbs.springws.test.common.XPathExpressionEvaluator;
import net.javacrumbs.springws.test.template.FreeMarkerTemplateProcessor;
import net.javacrumbs.springws.test.template.TemplateProcessor;
import net.javacrumbs.springws.test.template.XsltTemplateProcessor;
import net.javacrumbs.springws.test.util.DefaultXmlUtil;
import net.javacrumbs.springws.test.util.XmlUtil;

import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.soap.SoapEnvelopeException;
import org.springframework.ws.soap.SoapFault;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.xml.namespace.SimpleNamespaceContext;
import org.springframework.xml.validation.XmlValidator;
import org.springframework.xml.validation.XmlValidatorFactory;


/**
 * Contains methods simplifying message validation.
 * @author Lukas Krecan
 *
 */
public class MessageValidator {

	private static final String TRUE = Boolean.TRUE.toString();

	private final WebServiceMessage message;
	
    private ResourceLoader resourceLoader = new DefaultResourceLoader();

	private TemplateProcessor templateProcessor = new XsltTemplateProcessor();

	private SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
	
	private MessageComparator messageComparator = new DefaultMessageComparator();
	
	private SchemaValidator schemaValidator = new SchemaValidator();

	private String schemaLanguage = XmlValidatorFactory.SCHEMA_W3C_XML;
	
	private ExpressionEvaluator expressionEvaluator = new XPathExpressionEvaluator();
	
	private XmlUtil xmlUtil = DefaultXmlUtil.getInstance();
	
	public MessageValidator(WebServiceMessage message) {
		this.message = message;
	}
	
	public MessageValidator compare(String controlResourcePath) {
		return compare(getResource(controlResourcePath));
	}

	public MessageValidator compare(Resource controlResource) {
		try {
			messageComparator.compareMessage(message, preprocessResource(controlResource));
		} catch (IOException e) {
			processIOException(e);
		}
		return this;
	}

	protected void processIOException(IOException e) {
		throw new WsTestException("Error when comparing messages", e);
	}
		
	/**
	 * Validates if the message corresponds to given XSDs.
	 * @param message
	 */
	public MessageValidator validate(String schemaPath, String... schemaPaths) throws IOException {
		Resource[] schemas = new Resource[schemaPaths.length];
		for (int i = 0; i < schemas.length; i++) {
			schemas[i] = resourceLoader.getResource(schemaPaths[i]);
		}
		return validate(resourceLoader.getResource(schemaPath), schemas);
	}
	
	/**
	 * Validates if the message corresponds to given XSD.
	 * @param message
	 */
	public MessageValidator validate(Resource schema, Resource... schemas) throws IOException {
		
		Resource[] joinedSchemas = new Resource[schemas.length+1];
		joinedSchemas[0] = schema;
		System.arraycopy(schemas, 0, joinedSchemas, 1, schemas.length);
		
		validate(schemaValidator.createValidatorFromSchemas(joinedSchemas, schemaLanguage ));
		return this;
	}
	
	
	
	
	/**
	 * Validates message using generic {@link XmlValidator}. See {@link XmlValidatorFactory} for more details.
	 * @param validator
	 */
	public MessageValidator validate(XmlValidator xmlValidator) {
		try {
			schemaValidator.validate(message, xmlValidator);		
		} catch (IOException e) {
			processIOException(e);
		}
		return this;
	}
	
	/**
	 * Sets namespace mapping for all XPath validations like {@link #assertXPath(String)}
	 * @param namespaceMapping
	 * @return
	 */
	public MessageValidator useNamespaceMapping(Map namespaceMapping) {
		namespaceContext = new SimpleNamespaceContext();
		namespaceContext.setBindings(namespaceMapping);
		return this;
	}
	
	/**
	 * Adds mapping between prefix and namespace.
	 * @param prefix
	 * @param namespace
	 * @return
	 */
	public MessageValidator addNamespaceMapping(String prefix, String namespace)
	{
		namespaceContext.bindNamespaceUri(prefix, namespace);
		return this;
	}
	
	/**
	 * Asserts XPath expression. If the expression is not evaluated to true, throws {@link WsTestException}.
	 * It is possible to set namespace mapping using {@link #useNamespaceMapping(Map)}.
	 * @param xpath
	 * @return
	 */
	public MessageValidator assertXPath(String xpath) {
		return assertXPath(xpath, "Expression \""+xpath+"\" does not evaluate to true.");
	}
	/**
	 * Asserts XPath expression. If the expression is not evaluated to true, throws {@link WsTestException}.
	 * It is possible to set namespace mapping using {@link #useNamespaceMapping(Map)}.
	 * @param xpath
	 * @return
	 */
	public MessageValidator assertXPath(String xpath, String errorMessage) {
		if (!TRUE.equals(evaluateExpression(xpath)))
		{
			throw new WsTestException(errorMessage, message);
		}
		return this;
	}

	/**
	 * Evaluates expression
	 * @param expression
	 * @return
	 */
	protected String evaluateExpression(String expression) {
		return expressionEvaluator.evaluateExpression(xmlUtil.loadDocument(message), expression, null, namespaceContext);
	}
	

	/**
	 * Asserts that message is not SOAP fault.
	 * @return
	 */
	public MessageValidator assertNotSoapFault() {
		if (isSoapFault())
		{
			throw new WsTestException("Message is SOAP fault", message);
		}
		return this;
	}
	
	
	
	/**
	 * Assert that message is SOAP message (wrapped in SOAP envelope).
	 */
	public MessageValidator assertSoapMessage() {
		SoapMessage soapMessage = getSoapMessage();
		try
		{
			soapMessage.getEnvelope();
		}
		catch(SoapEnvelopeException e)
		{
			throw new WsTestException("Message is not a SOAP message",e);
		}
		return this;
	}
	/**
	 * Assert that message is SOAP fault.
	 */
	public MessageValidator assertSoapFault() {
		if (!isSoapFault())
		{
			throw new WsTestException("Message is not SOAP fault", message);
		}
		return this;
	}

	/**
	 * Returns true if message is SOAP fault.
	 * @return
	 */
	protected boolean isSoapFault() {
		if (getSoapMessage().hasFault()) 
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/**
	 * Returns soap message.
	 * @return
	 */
	public SoapMessage getSoapMessage() {
		if (message instanceof SoapMessage)
		{
			return (SoapMessage)message;
		}
		else
		{
			throw new WsTestException("The message is not SOAP message");
		}
	}
	
	/**
	 * Returns SOAP fault.
	 * @return
	 */
	public SoapFault getSoapFault() {
		assertSoapFault();	
		return getSoapMessage().getSoapBody().getFault();
	}
	
	/**
	 * Compares fault code.
	 * @param expectedFaultCode
	 * @return
	 */
	public MessageValidator assertFaultCode(String expectedFaultCode) {
		String faultCode = getSoapFault().getFaultCode().getLocalPart();
		if (!expectedFaultCode.equals(faultCode))
		{
			throw new WsTestException("Expected fault code \""+expectedFaultCode+"\", get \""+faultCode+"\"", message);
		}
		return this;
	}

	/**
	 * Compares fault string or reason. See {@link SoapFault#getFaultStringOrReason()}.
	 * @param expectedStringOrReason
	 * @return 
	 */
	public MessageValidator assertFaultStringOrReason(String expectedStringOrReason) {
		String faultStringOrReason = getSoapFault().getFaultStringOrReason();
		if (!expectedStringOrReason.equals(faultStringOrReason))
		{
			throw new WsTestException("Expected fault string or reason \""+expectedStringOrReason+"\", get \""+faultStringOrReason+"\"", message);
		}
		return this;
	}
	/**
	 * Compares fault actor or role. See {@link SoapFault#getFaultActorOrRole()}.
	 * @param expectedActorOrRole
	 * @return 
	 */
	public MessageValidator assertFaultActorOrRole(String expectedActorOrRole) {
		String faultActorOrRole = getSoapFault().getFaultActorOrRole();
		if (!expectedActorOrRole.equals(faultActorOrRole))
		{
			throw new WsTestException("Expected fault actor or role \""+expectedActorOrRole+"\", get \""+faultActorOrRole+"\"", message);
		}
		return this;
	}
	
	/**
	 * Asserts that the message contains element with given name. Namespace is ignored.
	 * @param elementName
	 * @return 
	 */
	public MessageValidator assertContainElement(String elementName) {
		return assertXPath("count(//*[local-name()='"+elementName+"'])>0", "Element \""+elementName+"\" not found.");
	}

	/**
	 * Asserts that message does not contain given element. Namespace is ignored.
	 * @param string
	 * @return 
	 */
	public MessageValidator assertNotContainElement(String elementName) {
		return assertXPath("count(//*[local-name()='"+elementName+"'])=0", "Element \""+elementName+"\" found.");
	}
	

	/**
	 * Asserts that the message contains given reqular expression. The message is processed as text, so whitespaces are taken into account
	 * @param string
	 * @return 
	 */
	public MessageValidator assertContain(String regexp) {
		if (!contains(regexp))
		{
			throw new WsTestException("Message does not contain regular expression \""+regexp+"\"", message);
		}
		return this;
	}
	
	/**
	 * Asserts that the message does not contain given reqular expression. The message is processed as text, so whitespaces are taken into account
	 * @param string
	 * @return 
	 * @return 
	 */
	public MessageValidator assertNotContain(String regexp) {
		if (contains(regexp))
		{
			throw new WsTestException("Message contains regular expression \""+regexp+"\"", message);
		}
		return this;
	}
	/**
	 * Returns true if message contains regexp.
	 * @param regexp
	 * @return 
	 */
	private boolean contains(String regexp) {
		String messageAsText = xmlUtil.serializeDocument(message);
		Pattern pattern = Pattern.compile(regexp);
		return pattern.matcher(messageAsText).find();
	}


	
	/**
	 * Does resource preprocessing. In default implementation just evaluates a template.
	 * @param resource
	 * @return
	 * @throws IOException
	 */
	protected Resource preprocessResource(Resource resource) throws IOException {
		return templateProcessor.processTemplate(resource, null);
	}


	protected Resource getResource(String resourcePath) {
		return resourceLoader.getResource(resourcePath);
	}
	
	public ResourceLoader getResourceLoader() {
		return resourceLoader;
	}

	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}

	public TemplateProcessor getTemplateProcessor() {
		return templateProcessor;
	}

	public void setTemplateProcessor(TemplateProcessor templateProcessor) {
		this.templateProcessor = templateProcessor;
	}
	
	public MessageValidator useTemplateProcessor(TemplateProcessor templateProcessor) {
		setTemplateProcessor(templateProcessor);
		return this;
	}
	
	/**
	 * From now on use FreeMarker for templates.
	 * @return
	 */
	public MessageValidator useFreeMarkerTemplateProcessor() {
		FreeMarkerTemplateProcessor freemarkerTemplateProcessor = new FreeMarkerTemplateProcessor();
		freemarkerTemplateProcessor.setResourceLoader(resourceLoader);
		freemarkerTemplateProcessor.afterPropertiesSet();
		return useTemplateProcessor(freemarkerTemplateProcessor);
	}
	
	
	
	/**
	 * From now on use XSLT for templates.
	 * @return
	 */
	public MessageValidator useXsltTemplateProcessor() {
		return useTemplateProcessor(new XsltTemplateProcessor());
	}

	public WebServiceMessage getMessage() {
		return message;
	}

	public MessageComparator getMessageComparator() {
		return messageComparator;
	}

	public void setMessageComparator(MessageComparator messageComparator) {
		this.messageComparator = messageComparator;
	}

	public MessageValidator useMessageComparator(MessageComparator messageComparator) {
		setMessageComparator(messageComparator);
		return this;
	}

	public SchemaValidator getSchemaValidator() {
		return schemaValidator;
	}

	public void setSchemaValidator(SchemaValidator schemaValidator) {
		this.schemaValidator = schemaValidator;
	}

	public MessageValidator useSchemaValidator(SchemaValidator schemaValidator) {
		setSchemaValidator(schemaValidator);
		return this;
	}

	public String getSchemaLanguage() {
		return schemaLanguage;
	}

	public void setSchemaLanguage(String schemaLanguage) {
		this.schemaLanguage = schemaLanguage;
	}
	public MessageValidator useSchemaLanguage(String schemaLanguage) {
		setSchemaLanguage(schemaLanguage);
		return this;		
	}

	public ExpressionEvaluator getExpressionEvaluator() {
		return expressionEvaluator;
	}

	public void setExpressionEvaluator(ExpressionEvaluator expressionEvaluator) {
		this.expressionEvaluator = expressionEvaluator;
	}

	public MessageValidator useExpressionEvaluator(ExpressionEvaluator expressionEvaluator) {
		setExpressionEvaluator(expressionEvaluator);
		return this;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy