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

io.codearte.accurest.util.ContentUtils.groovy Maven / Gradle / Ivy

package io.codearte.accurest.util
import groovy.json.JsonException
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import groovy.transform.TypeChecked
import groovy.util.logging.Slf4j
import io.codearte.accurest.dsl.internal.DslProperty
import io.codearte.accurest.dsl.internal.ExecutionProperty
import io.codearte.accurest.dsl.internal.Headers
import io.codearte.accurest.dsl.internal.MatchingStrategy
import io.codearte.accurest.dsl.internal.NamedProperty
import io.codearte.accurest.dsl.internal.OptionalProperty
import org.codehaus.groovy.runtime.GStringImpl

import java.util.regex.Matcher
import java.util.regex.Pattern

import static org.apache.commons.lang3.StringEscapeUtils.escapeJava
import static org.apache.commons.lang3.StringEscapeUtils.escapeJson
import static org.apache.commons.lang3.StringEscapeUtils.escapeXml11

@TypeChecked
@Slf4j
class ContentUtils {

	public static final Closure GET_STUB_SIDE = {
		it instanceof DslProperty ? it.clientValue : it
	}

	public static final Closure GET_TEST_SIDE = {
		it instanceof DslProperty ? it.serverValue : it
	}

	private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern.compile('.*REGEXP>>(.*)<<.*')
	private static final Pattern TEMPORARY_EXECUTION_PATTERN_HOLDER = Pattern.compile('["]?EXECUTION>>(.*)<<["]?')
	private static final Pattern TEMPORARY_OPTIONAL_PATTERN_HOLDER = Pattern.compile('OPTIONAL>>(.*)<<')
	private static final String JSON_VALUE_PATTERN_FOR_REGEX = 'REGEXP>>%s<<'
	private static final String JSON_VALUE_PATTERN_FOR_OPTIONAL = 'OPTIONAL>>%s<<'
	private static final String JSON_VALUE_PATTERN_FOR_EXECUTION = '"EXECUTION>>%s<<"'

	/**
	 * Due to the fact that we allow users to have a body with GString and different values inside
	 * we need to be prepared that they pass regexps around both on client and server side.
	 *
	 * In order to preserve the original JSON structure we need to convert the passed Regex patterns
	 * to a temporary string, then convert all to a legitimate JSON structure and then finally
	 * convert it back from string to a pattern.
	 *
	 * @param bodyAsValue - GString with passed values
	 * @param valueProvider - provider of values either for server or client side
	 * @return JSON structure with replaced client / server side parts
	 */
	public static Object extractValue(GString bodyAsValue, ContentType contentType, Closure valueProvider) {
		if (bodyAsValue.isEmpty()){
			return bodyAsValue
		}
		if (contentType == ContentType.JSON) {
			return extractValueForJSON(bodyAsValue, valueProvider)
		}
		if (contentType == ContentType.XML) {
			return extractValueForXML(bodyAsValue, valueProvider)
		}
		// else Brute force :(
		try {
			log.debug("No content type provided so trying to parse as JSON")
			return extractValueForJSON(bodyAsValue, valueProvider)
		} catch(JsonException e) {
			// Not a JSON format
			log.debug("Failed to parse as JSON - trying to parse as XML", e)
			try {
				return extractValueForXML(bodyAsValue, valueProvider)
			} catch (Exception exception) {
				log.debug("No content type provided and failed to parse as XML - returning the value back to the user", exception)
				return extractValueForGString(bodyAsValue, valueProvider)
			}
		}
	}

	public static ContentType getClientContentType(GString bodyAsValue) {
		try {
			extractValueForJSON(bodyAsValue, GET_STUB_SIDE)
			return ContentType.JSON
		} catch(JsonException e) {
			try {
				new XmlSlurper().parseText(extractValueForXML(bodyAsValue, GET_STUB_SIDE).toString())
				return ContentType.XML
			} catch (Exception exception) {
				extractValueForGString(bodyAsValue, GET_STUB_SIDE)
				return ContentType.UNKNOWN
			}
		}
	}

	public static ContentType getClientContentType(String bodyAsValue) {
		try {
			new JsonSlurper().parseText(bodyAsValue)
			return ContentType.JSON
		} catch(JsonException e) {
			try {
				new XmlSlurper().parseText(bodyAsValue)
				return ContentType.XML
			} catch (Exception exception) {
				return ContentType.UNKNOWN
			}
		}
	}

	public static ContentType getClientContentType(Object bodyAsValue) {
		return ContentType.UNKNOWN
	}

	public static ContentType getClientContentType(Map bodyAsValue) {
		try {
			JsonOutput.toJson(bodyAsValue)
			return ContentType.JSON
		} catch (Exception ignore) {
			return ContentType.UNKNOWN
		}
	}

	public static ContentType getClientContentType(List bodyAsValue) {
		try {
			JsonOutput.toJson(bodyAsValue)
			return ContentType.JSON
		} catch (Exception ignore) {
			return ContentType.UNKNOWN
		}
	}

	private static GStringImpl extractValueForGString(GString bodyAsValue, Closure valueProvider) {
		return new GStringImpl(
				bodyAsValue.values.collect { it instanceof DslProperty ? valueProvider(it) : it } as String[],
				bodyAsValue.strings.clone() as String[]
		)
	}

	public static Object extractValue(GString bodyAsValue, Closure valueProvider) {
		return extractValue(bodyAsValue, ContentType.UNKNOWN, valueProvider)
	}

	private static Object extractValueForJSON(GString bodyAsValue, Closure valueProvider) {
		GString transformedString = new GStringImpl(
				bodyAsValue.values.collect { transformJSONStringValue(it, valueProvider) } as String[],
				bodyAsValue.strings.clone() as String[]
		)
		def parsedJson = new JsonSlurper().parseText(transformedString.toString().replace('\\', '\\\\'))
		return convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson)
	}

	private static GStringImpl extractValueForXML(GString bodyAsValue, Closure valueProvider) {
		return new GStringImpl(
				bodyAsValue.values.collect { transformXMLStringValue(it, valueProvider) } as String[],
				bodyAsValue.strings.clone() as String[]
		)
	}

	protected static Object transformJSONStringValue(Object obj, Closure valueProvider) {
		return obj
	}

	protected static Object transformJSONStringValue(DslProperty dslProperty, Closure valueProvider) {
		return transformJSONStringValue(valueProvider(dslProperty), valueProvider)
	}

	protected static Object transformJSONStringValue(Pattern pattern, Closure valueProvider) {
		return String.format(JSON_VALUE_PATTERN_FOR_REGEX, pattern.pattern())
	}

	protected static Object transformJSONStringValue(OptionalProperty optional, Closure valueProvider) {
		return String.format(JSON_VALUE_PATTERN_FOR_OPTIONAL, optional.value)
	}

	protected static Object transformJSONStringValue(ExecutionProperty property, Closure valueProvider) {
		return String.format(JSON_VALUE_PATTERN_FOR_EXECUTION, property.executionCommand)
	}

	private static String transformXMLStringValue(Object obj, Closure valueProvider) {
		return escapeXml11(obj.toString())
	}

	private static String transformXMLStringValue(DslProperty dslProperty, Closure valueProvider) {
		return transformXMLStringValue(valueProvider(dslProperty), valueProvider)
	}

	protected static Object convertDslPropsToTemporaryRegexPatterns(parsedJson) {
		MapConverter.transformValues(parsedJson, { Object value ->
			return transformJSONStringValue(value, GET_TEST_SIDE)
		})
	}

	private static Object convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) {
		MapConverter.transformValues(parsedJson, { Object value ->
			if (value instanceof String) {
				String string = (String) value
				return returnParsedObject(string)
			}
			return value
		})
	}

	/**
	 * 

* If you wonder why there is val[1] without null-check then take a look at this: *

*

* Example: *

*

* Our string equals: {@code EXECUTION>>assertThatRejectionReasonIsNull($it)<<} * The matcher matches this group with the pattern {@code EXECUTION>>(.*)<<} *

*

* So {@code executionMatcher[0]} returns 2 elements: *

    *
  • index0: EXECUTION>>assertThatRejectionReasonIsNull($it)<<
  • *
  • index1: assertThatRejectionReasonIsNull($it)<<
  • *
*

*

* Thus one can safely write {@code executionMatcher[0][1]} to retrieve the matched group *

* @param string to match the regexps against * @return object converted from temporary holders */ static Object returnParsedObject(Object object) { if (!(object instanceof String)) { return object } String string = (String) object Matcher matcher = TEMPORARY_PATTERN_HOLDER.matcher(string.trim()) if (matcher.matches()) { return Pattern.compile(patternFromMatchingGroup(matcher)) } Matcher executionMatcher = TEMPORARY_EXECUTION_PATTERN_HOLDER.matcher(string.trim()) if (executionMatcher.matches()) { return new ExecutionProperty(patternFromMatchingGroup(executionMatcher)) } Matcher optionalMatcher = TEMPORARY_OPTIONAL_PATTERN_HOLDER.matcher(string.trim()) if (optionalMatcher.matches()) { String patternToMatch = patternFromMatchingGroup(optionalMatcher) return Pattern.compile(new OptionalProperty(patternToMatch).optionalPattern()) } return string } private static String patternFromMatchingGroup(Matcher matcher) { List val = matcher[0] as List return val[1] } public static ContentType recognizeContentTypeFromHeader(Headers headers) { String content = headers?.entries.find { it.name == "Content-Type" } ?.clientValue?.toString() if (content?.endsWith("json")) { return ContentType.JSON } if (content?.endsWith("xml")) { return ContentType.XML } return ContentType.UNKNOWN } public static MatchingStrategy.Type getEqualsTypeFromContentType(ContentType contentType) { switch (contentType) { case ContentType.JSON: return MatchingStrategy.Type.EQUAL_TO_JSON case ContentType.XML: return MatchingStrategy.Type.EQUAL_TO_XML } return MatchingStrategy.Type.EQUAL_TO } public static ContentType recognizeContentTypeFromContent(GString gstring) { if (isJsonType(gstring)) { return ContentType.JSON } if (isXmlType(gstring)) { return ContentType.XML } return ContentType.UNKNOWN } public static ContentType recognizeContentTypeFromContent(Map jsonMap) { return ContentType.JSON } public static ContentType recognizeContentTypeFromContent(List jsonList) { return ContentType.JSON } public static ContentType recognizeContentTypeFromContent(String string) { try { new JsonSlurper().parseText(string) return ContentType.JSON } catch (Exception e){ return ContentType.UNKNOWN } } public static ContentType recognizeContentTypeFromContent(Object gstring) { return ContentType.UNKNOWN } public static boolean isJsonType(GString gstring) { if (gstring.isEmpty()) { return false } GString stringWithoutValues = new GStringImpl( gstring.values.collect({ it instanceof String || it instanceof GString ? it.toString() : escapeJson(it.toString()) }) as Object[], gstring.strings.clone() as String[] ) try { new JsonSlurper().parseText(stringWithoutValues.toString()) return true } catch (JsonException e) { // Not JSON } return false } public static boolean isXmlType(GString gstring) { GString stringWithoutValues = new GStringImpl( gstring.values.collect({ it instanceof String || it instanceof GString ? it.toString() : escapeXml11(it.toString()) }) as Object[], gstring.strings.clone() as String[] ) try { new XmlSlurper().parseText(stringWithoutValues.toString()) return true } catch (Exception e) { // Not XML } return false } public static ContentType recognizeContentTypeFromMatchingStrategy(MatchingStrategy.Type type) { switch (type) { case MatchingStrategy.Type.EQUAL_TO_XML: return ContentType.XML case MatchingStrategy.Type.EQUAL_TO_JSON: return ContentType.JSON } return ContentType.UNKNOWN } static String getGroovyMultipartFileParameterContent(String propertyName, NamedProperty propertyValue) { return "'$propertyName', '$propertyValue.name.serverValue', '$propertyValue.value.serverValue'.bytes" } static String getJavaMultipartFileParameterContent(String propertyName, NamedProperty propertyValue) { return """"${escapeJava(propertyName)}", "${escapeJava(propertyValue.name.serverValue as String)}", "${escapeJava(propertyValue.value.serverValue as String)}".getBytes()""" } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy