/*
* Copyright (c) 2012 - 2016 Jadler contributors
* This program is made available under the terms of the MIT License.
*/
package net.jadler.stubbing;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
import net.jadler.KeyValues;
import org.apache.commons.lang.Validate;
import static org.apache.commons.lang.StringUtils.abbreviate;
/**
* Definition of a stub http response. For creating new instances use the {@link #builder()} static method.
*/
public class StubResponse {
private final KeyValues headers;
private final byte[] body;
private final Charset encoding;
private final int status;
private final long delayValue;
private final TimeUnit delayUnit;
/**
* An empty stub response containing nothing but defaults (empty body, http status 200, no headers and no delay)
*/
public static final StubResponse EMPTY = builder().build();
private StubResponse(final int status, final byte[] body, final Charset encoding,
final KeyValues headers, final long delayValue, final TimeUnit delayUnit) {
this.status = status;
this.body = body;
this.encoding = encoding;
this.headers = headers;
this.delayValue = delayValue;
this.delayUnit = delayUnit;
}
/**
* @return http status of the stub response
*/
public int getStatus() {
return this.status;
}
/**
* @return response body as an array of bytes
*/
public byte[] getBody() {
return this.body.clone();
}
/**
* @return encoding of the body ({@code null} if not set)
*/
public Charset getEncoding() {
return this.encoding;
}
/**
* @return stub response headers
*/
public KeyValues getHeaders() {
return this.headers;
}
/**
* @return a delay (in millis) this stub response will be returned after
*/
public long getDelay() {
return this.delayUnit.toMillis(this.delayValue);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder()
.append("status=")
.append(this.status)
.append(", body=");
if (this.body.length > 0) {
if (this.encoding != null) {
sb.append(abbreviate(new String(this.body, this.encoding), 13));
sb.append(", encoding=").append(this.encoding);
}
else {
sb.append("<binary>");
}
}
else {
sb.append("<empty>");
}
sb.append(", headers=(").append(this.headers.toString());
sb.append("), delay=").append(this.delayValue).append(" ").append(this.delayUnit.toString().toLowerCase());
return sb.toString();
}
/**
* @return new builder for creating {@link StubResponse} instances
*/
public static Builder builder() {
return new Builder();
}
/**
* A builder class for creating new {@link StubResponse} instances.
*/
public static class Builder {
private int status;
private byte[] body;
private Charset encoding;
private KeyValues headers;
private long delayValue;
private TimeUnit delayUnit;
/**
* Private constructor. Use {@link StubResponse#builder()} instead.
*/
private Builder() {
this.status = 200;
this.body = new byte[0];
this.encoding = null;
this.headers = new KeyValues();
this.delayValue = 0;
this.delayUnit = TimeUnit.MILLISECONDS;
}
/**
* Sets the stub response http status. If not called, {@code 200} will be used as a default.
* @param status stub response status (cannot be negative)
* @return this builder
*/
public Builder status(final int status) {
Validate.isTrue(status >= 0, "status cannot be negative");
this.status = status;
return this;
}
/**
* Sets the response body as an array of bytes. Calling this method resets all data
* previously provided by {@link #body(String, Charset)}. If the response body is not set at all, an empty
* body is used.
* @param body stub response body as an array of bytes (cannot be null).
* @return this builder
*/
public Builder body(final byte[] body) {
Validate.notNull(body, "body cannot be null, use an empty array instead");
this.body = body;
this.encoding = null;
return this;
}
/**
* Sets the response body as a string. Calling this method resets all data previously provided
* by {@link #body(byte[])}. If the response body is not set at all, an empty body is used.
* @param body stub response body as a string (cannot be {@code null})
* @param encoding encoding of the body (cannot be {@code null})
* @return this builder
*/
public Builder body(final String body, final Charset encoding) {
Validate.notNull(body, "body cannot be null, use an empty string instead");
Validate.notNull(encoding, "encoding cannot be null");
this.body = body.getBytes(encoding);
this.encoding = encoding;
return this;
}
/**
* Sets new stub response headers (all previously set headers are discarded).
* @param headers stub response headers (cannot be {@code null})
* @return this builder
*/
public Builder headers(final KeyValues headers) {
Validate.notNull(headers, "headers cannot be null");
this.headers = headers;
return this;
}
/**
* Adds a new stub response header. Supports multivalue headers (if a header with the same name has already been
* added before, adds another value to it)
* @param name header name (cannot be empty)
* @param value header value (cannot be {@code null}, however can be empty for valueless headers)
* @return this headers
*/
public Builder header(final String name, final String value) {
Validate.notEmpty(name, "name cannot be empty");
Validate.notNull(value, "value cannot be null, use an empty string instead");
this.headers = this.headers.add(name, value);
return this;
}
/**
* Sets the response delay. If not called {@code 0} will be used as a default.
* @param delayValue a delay (in units defined by the {@code delayUnit} parameter)
* this stub response will be returned after
* @param delayUnit unit of the delay parameter
* @return this builder
*/
public Builder delay(long delayValue, TimeUnit delayUnit) {
Validate.isTrue(delayValue >= 0, "delayValue cannot be negative");
Validate.notNull(delayUnit, "delayUnitCannot be null");
this.delayValue = delayValue;
this.delayUnit = delayUnit;
return this;
}
/**
* @return a {@link StubResponse} instance built from values stored in this builder
*/
public StubResponse build() {
return new StubResponse(this.status, this.body, this.encoding, this.headers,
this.delayValue, this.delayUnit);
}
}
}