package io.github.azagniotov.stubby4j.stubs;
import io.github.azagniotov.stubby4j.annotations.CoberturaIgnore;
import io.github.azagniotov.stubby4j.annotations.VisibleForTesting;
import io.github.azagniotov.stubby4j.utils.FileUtils;
import io.github.azagniotov.stubby4j.utils.StringUtils;
import org.eclipse.jetty.http.HttpStatus.Code;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import static io.github.azagniotov.generics.TypeSafeConverter.asCheckedLinkedHashMap;
import static io.github.azagniotov.stubby4j.utils.FileUtils.fileToBytes;
import static io.github.azagniotov.stubby4j.utils.FileUtils.isFilePathContainTemplateTokens;
import static io.github.azagniotov.stubby4j.utils.ObjectUtils.isNull;
import static io.github.azagniotov.stubby4j.yaml.ConfigurableYAMLProperty.BODY;
import static io.github.azagniotov.stubby4j.yaml.ConfigurableYAMLProperty.FILE;
import static io.github.azagniotov.stubby4j.yaml.ConfigurableYAMLProperty.HEADERS;
import static io.github.azagniotov.stubby4j.yaml.ConfigurableYAMLProperty.LATENCY;
import static io.github.azagniotov.stubby4j.yaml.ConfigurableYAMLProperty.STATUS;
import static java.lang.Integer.parseInt;
import static org.eclipse.jetty.http.HttpStatus.getCode;
public class StubResponse implements ReflectableStub {
public static final String STUBBY_RESOURCE_ID_HEADER = "x-stubby-resource-id";
private final Code httpStatusCode;
private final String body;
private final File file;
private final byte[] fileBytes;
private final String latency;
private final Map<String, String> headers;
private StubResponse(final Code httpStatusCode,
final String body,
final File file,
final String latency,
final Map<String, String> headers) {
this.httpStatusCode = httpStatusCode;
this.body = body;
this.file = file;
this.fileBytes = isNull(file) ? new byte[]{} : getFileBytes();
this.latency = latency;
this.headers = isNull(headers) ? new LinkedHashMap<>() : headers;
}
public static StubResponse okResponse() {
return new StubResponse.Builder().build();
}
public static StubResponse notFoundResponse() {
return new StubResponse.Builder().withHttpStatusCode(Code.NOT_FOUND).build();
}
public static StubResponse unauthorizedResponse() {
return new StubResponse.Builder().withHttpStatusCode(Code.UNAUTHORIZED).build();
}
public static StubResponse redirectResponse(final Optional<StubResponse> stubResponseOptional) {
if (!stubResponseOptional.isPresent()) {
return new StubResponse.Builder().withHttpStatusCode(Code.MOVED_PERMANENTLY).build();
}
final StubResponse foundStubResponse = stubResponseOptional.get();
return new StubResponse(
foundStubResponse.getHttpStatusCode(),
foundStubResponse.getBody(),
foundStubResponse.getRawFile(),
foundStubResponse.getLatency(),
foundStubResponse.getHeaders());
}
public Code getHttpStatusCode() {
return httpStatusCode;
}
public String getBody() {
return (StringUtils.isSet(body) ? body : "");
}
public boolean isRecordingRequired() {
final String body = getBody();
return StringUtils.toLower(body).startsWith("http");
}
public Map<String, String> getHeaders() {
return headers;
}
public String getLatency() {
return latency;
}
/**
* Used by reflection when populating stubby admin page with stubbed information
*/
public byte[] getFile() {
return fileBytes;
}
public File getRawFile() {
return file;
}
public String getRawFileAbsolutePath() {
return file.getAbsolutePath();
}
public byte[] getResponseBodyAsBytes() {
if (fileBytes.length == 0) {
return StringUtils.getBytesUtf8(getBody());
}
return fileBytes;
}
public boolean isBodyContainsTemplateTokens() {
final boolean isFileTemplate = fileBytes.length != 0 && isTemplateFile();
return isFileTemplate || StringUtils.isTokenized(getBody());
}
public boolean isFilePathContainsTemplateTokens() {
try {
return isFilePathContainTemplateTokens(file);
} catch (Exception e) {
return false;
}
}
@CoberturaIgnore
private boolean isTemplateFile() {
try {
return FileUtils.isTemplateFile(file);
} catch (Exception e) {
return false;
}
}
@CoberturaIgnore
private byte[] getFileBytes() {
try {
return fileToBytes(file);
} catch (Exception e) {
return new byte[]{};
}
}
public boolean hasHeaderLocation() {
return getHeaders().containsKey("location");
}
void addResourceIDHeader(final int resourceIndex) {
getHeaders().put(STUBBY_RESOURCE_ID_HEADER, String.valueOf(resourceIndex));
}
String getResourceIDHeader() {
return getHeaders().get(StubResponse.STUBBY_RESOURCE_ID_HEADER);
}
public static final class Builder extends AbstractBuilder<StubResponse> {
private String status;
private String body;
private File file;
private String latency;
private Map<String, String> headers;
public Builder() {
super();
this.status = null;
this.body = null;
this.file = null;
this.latency = null;
this.headers = new LinkedHashMap<>();
}
public Builder emptyWithBody(final String body) {
this.status = String.valueOf(Code.OK.getCode());
this.body = body;
return this;
}
public Builder withHttpStatusCode(final Code httpStatusCode) {
this.status = String.valueOf(httpStatusCode.getCode());
return this;
}
public Builder withBody(final String body) {
this.body = body;
return this;
}
public Builder withFile(final File file) {
this.file = file;
return this;
}
@Override
public StubResponse build() {
this.status = getStaged(String.class, STATUS, status);
this.body = getStaged(String.class, BODY, body);
this.file = getStaged(File.class, FILE, file);
this.latency = getStaged(String.class, LATENCY, latency);
this.headers = asCheckedLinkedHashMap(getStaged(Map.class, HEADERS, headers), String.class, String.class);
final StubResponse stubResponse = new StubResponse(getHttpStatusCode(), body, file, latency, headers);
this.status = null;
this.body = null;
this.file = null;
this.latency = null;
this.headers = new LinkedHashMap<>();
this.fieldNameAndValues.clear();
return stubResponse;
}
@VisibleForTesting
Code getHttpStatusCode() {
return isNull(this.status) ? Code.OK : getCode(parseInt(this.status));
}
}
}