Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
A Java-based HTTP stub server
Copyright (C) 2012 Alexander Zagniotov, Isa Goksu and Eric Mrak
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
package by.stub.yaml.stubs;
import by.stub.annotations.CoberturaIgnore;
import by.stub.annotations.VisibleForTesting;
import by.stub.utils.CollectionUtils;
import by.stub.utils.FileUtils;
import by.stub.utils.HandlerUtils;
import by.stub.utils.ObjectUtils;
import by.stub.utils.StringUtils;
import by.stub.yaml.YamlProperties;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* @author Alexander Zagniotov
* @since 6/14/12, 1:09 AM
*/
public class StubRequest {
public static final String AUTH_HEADER = "authorization";
private final String url;
private final String post;
private final File file;
private final byte[] fileBytes;
private final List method;
private final Map headers;
private final Map query;
private final Map regexGroups;
public StubRequest(final String url,
final String post,
final File file,
final List method,
final Map headers,
final Map query) {
this.url = url;
this.post = post;
this.file = file;
this.fileBytes = ObjectUtils.isNull(file) ? new byte[]{} : getFileBytes();
this.method = ObjectUtils.isNull(method) ? new ArrayList() : method;
this.headers = ObjectUtils.isNull(headers) ? new LinkedHashMap() : headers;
this.query = ObjectUtils.isNull(query) ? new LinkedHashMap() : query;
this.regexGroups = new TreeMap();
}
public final ArrayList getMethod() {
final ArrayList uppercase = new ArrayList(method.size());
for (final String string : method) {
uppercase.add(StringUtils.toUpper(string));
}
return uppercase;
}
public void addMethod(final String newMethod) {
if (StringUtils.isSet(newMethod)) {
method.add(newMethod);
}
}
public String getUrl() {
if (getQuery().isEmpty()) {
return url;
}
final String queryString = CollectionUtils.constructQueryString(query);
return String.format("%s?%s", url, queryString);
}
private byte[] getFileBytes() {
try {
return FileUtils.fileToBytes(file);
} catch (Exception e) {
return new byte[]{};
}
}
public String getPostBody() {
if (fileBytes.length == 0) {
return FileUtils.enforceSystemLineSeparator(post);
}
final String utf8FileContent = StringUtils.newStringUtf8(fileBytes);
return FileUtils.enforceSystemLineSeparator(utf8FileContent);
}
//Used by reflection when populating stubby admin page with stubbed information
public String getPost() {
return post;
}
public final Map getHeaders() {
final Map headersCopy = new LinkedHashMap(headers);
final Set> entrySet = headersCopy.entrySet();
this.headers.clear();
for (final Map.Entry entry : entrySet) {
this.headers.put(StringUtils.toLower(entry.getKey()), entry.getValue());
}
return headers;
}
public Map getQuery() {
return query;
}
public byte[] getFile() {
return fileBytes;
}
// Just a shallow copy that protects collection from modification, the points themselves are not copied
public Map getRegexGroups() {
return new TreeMap(regexGroups);
}
public File getRawFile() {
return file;
}
public boolean hasHeaders() {
return !getHeaders().isEmpty();
}
public boolean hasQuery() {
return !getQuery().isEmpty();
}
public boolean hasPostBody() {
return StringUtils.isSet(getPostBody());
}
public static StubRequest newStubRequest() {
return new StubRequest(null, null, null, null, null, null);
}
public static StubRequest newStubRequest(final String url, final String post) {
return new StubRequest(url, post, null, null, null, null);
}
public static StubRequest createFromHttpServletRequest(final HttpServletRequest request) throws IOException {
final StubRequest assertionRequest = StubRequest.newStubRequest(request.getPathInfo(),
HandlerUtils.extractPostRequestBody(request, "stubs"));
assertionRequest.addMethod(request.getMethod());
final Enumeration headerNamesEnumeration = request.getHeaderNames();
final List headerNames = ObjectUtils.isNotNull(headerNamesEnumeration)
? Collections.list(request.getHeaderNames()) : new LinkedList();
for (final String headerName : headerNames) {
final String headerValue = request.getHeader(headerName);
assertionRequest.getHeaders().put(StringUtils.toLower(headerName), headerValue);
}
assertionRequest.getQuery().putAll(CollectionUtils.constructParamMap(request.getQueryString()));
return assertionRequest;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
} else if (o instanceof StubRequest) {
final StubRequest dataStoreRequest = (StubRequest) o;
return urlsMatch(dataStoreRequest.url, this.url)
&& arraysIntersect(dataStoreRequest.getMethod(), this.getMethod())
&& postBodiesMatch(dataStoreRequest.getPostBody(), this.getPostBody())
&& headersMatch(dataStoreRequest.getHeaders(), this.getHeaders())
&& queriesMatch(dataStoreRequest.getQuery(), this.getQuery());
}
return false;
}
private boolean urlsMatch(final String dataStoreUrl, final String thisAssertingUrl) {
return stringsMatch(dataStoreUrl, thisAssertingUrl, YamlProperties.URL);
}
private boolean postBodiesMatch(final String dataStorePostBody, final String thisAssertingPostBody) {
return stringsMatch(dataStorePostBody, thisAssertingPostBody, YamlProperties.POST);
}
private boolean queriesMatch(final Map dataStoreQuery, final Map thisAssertingQuery) {
return mapsMatch(dataStoreQuery, thisAssertingQuery, YamlProperties.QUERY);
}
private boolean headersMatch(final Map dataStoreHeaders, final Map thisAssertingHeaders) {
final Map dataStoreHeadersCopy = new HashMap(dataStoreHeaders);
dataStoreHeadersCopy.remove(StubRequest.AUTH_HEADER); //Auth header dealt with in StubbedDataManager after request was matched
return mapsMatch(dataStoreHeadersCopy, thisAssertingHeaders, YamlProperties.HEADERS);
}
@VisibleForTesting
boolean mapsMatch(final Map dataStoreMap, final Map thisAssertingMap, final String mapName) {
if (dataStoreMap.isEmpty()) {
return true;
} else if (thisAssertingMap.isEmpty()) {
return false;
}
final Map dataStoreMapCopy = new HashMap(dataStoreMap);
final Map assertingMapCopy = new HashMap(thisAssertingMap);
for (Map.Entry dataStoreParam : dataStoreMapCopy.entrySet()) {
final boolean containsRequiredParam = assertingMapCopy.containsKey(dataStoreParam.getKey());
if (!containsRequiredParam) {
return false;
} else {
final String assertedQueryValue = assertingMapCopy.get(dataStoreParam.getKey());
final String templateTokenName = String.format("%s.%s", mapName, dataStoreParam.getKey());
if (!stringsMatch(dataStoreParam.getValue(), assertedQueryValue, templateTokenName)) {
return false;
}
}
}
return true;
}
@VisibleForTesting
boolean stringsMatch(final String dataStoreValue, final String thisAssertingValue, final String templateTokenName) {
final boolean isDataStoreValueSet = StringUtils.isSet(dataStoreValue);
final boolean isAssertingValueSet = StringUtils.isSet(thisAssertingValue);
if (!isDataStoreValueSet) {
return true;
} else if (!isAssertingValueSet) {
return false;
} else if (StringUtils.isWithinSquareBrackets(dataStoreValue)) {
return dataStoreValue.equals(thisAssertingValue);
} else {
return regexMatch(dataStoreValue, thisAssertingValue, templateTokenName);
}
}
private boolean regexMatch(final String dataStoreValue, final String thisAssertingValue, final String templateTokenName) {
try {
// Pattern.MULTILINE changes the behavior of '^' and '$' characters,
// it does not mean that newline feeds and carriage return will be matched by default
// You need to make sure that you regex pattern covers both \r (carriage return) and \n (linefeed).
// It is achievable by using symbol '\s+' which covers both \r (carriage return) and \n (linefeed).
final Matcher matcher = Pattern.compile(dataStoreValue, Pattern.MULTILINE).matcher(thisAssertingValue);
final boolean isMatch = matcher.matches();
if (isMatch) {
// group(0) holds the full regex match
regexGroups.put(StringUtils.buildToken(templateTokenName, 0), matcher.group(0));
//Matcher.groupCount() returns the number of explicitly defined capturing groups in the pattern regardless
// of whether the capturing groups actually participated in the match. It does not include matcher.group(0)
final int groupCount = matcher.groupCount();
if (groupCount > 0) {
for (int idx = 1; idx <= groupCount; idx++) {
regexGroups.put(StringUtils.buildToken(templateTokenName, idx), matcher.group(idx));
}
}
}
return isMatch;
} catch (PatternSyntaxException e) {
return dataStoreValue.equals(thisAssertingValue);
}
}
@VisibleForTesting
boolean arraysIntersect(final ArrayList dataStoreArray, final ArrayList thisAssertingArray) {
if (dataStoreArray.isEmpty()) {
return true;
} else if (!thisAssertingArray.isEmpty()) {
for (final String entry : thisAssertingArray) {
if (dataStoreArray.contains(entry)) {
return true;
}
}
}
return false;
}
@Override
@CoberturaIgnore
public int hashCode() {
int result = (ObjectUtils.isNotNull(url) ? url.hashCode() : 0);
result = 31 * result + method.hashCode();
result = 31 * result + (ObjectUtils.isNotNull(post) ? post.hashCode() : 0);
result = 31 * result + (ObjectUtils.isNotNull(fileBytes) && fileBytes.length != 0 ? Arrays.hashCode(fileBytes) : 0);
result = 31 * result + headers.hashCode();
result = 31 * result + query.hashCode();
return result;
}
@Override
@CoberturaIgnore
public final String toString() {
final StringBuffer sb = new StringBuffer();
sb.append("StubRequest");
sb.append("{url=").append(url);
sb.append(", method=").append(method);
if (!ObjectUtils.isNull(post)) {
sb.append(", post=").append(post);
}
sb.append(", query=").append(query);
sb.append(", headers=").append(getHeaders());
sb.append('}');
return sb.toString();
}
}