package org.baeldung.test.common.client.template;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.http.HttpHeaders;
import org.baeldung.client.marshall.IMarshaller;
import org.baeldung.client.util.SearchUriBuilder;
import org.baeldung.common.interfaces.IDto;
import org.baeldung.common.search.ClientOperation;
import org.baeldung.common.util.QueryConstants;
import org.baeldung.common.web.WebConstants;
import org.baeldung.test.common.client.security.ITestAuthenticator;
import org.baeldung.test.common.search.SearchTestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.jayway.restassured.response.Response;
import com.jayway.restassured.specification.RequestSpecification;
@SuppressWarnings({ "unchecked", "rawtypes" })
public abstract class AbstractRestClient<T extends IDto> implements IRestClient<T> {
protected final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
protected IMarshaller marshaller;
@Autowired
protected ITestAuthenticator auth;
protected final Class<T> clazz;
public AbstractRestClient(final Class<T> clazz) {
Preconditions.checkNotNull(clazz);
this.clazz = clazz;
}
// find - one
@Override
public final T findOne(final long id) {
final String uriOfResource = getUri() + WebConstants.PATH_SEP + id;
return findOneByUri(uriOfResource);
}
@Override
public final Response findOneAsResponse(final long id) {
return findOneAsResponse(id, null);
}
final Response findOneAsResponse(final long id, final RequestSpecification req) {
final String uriOfResource = getUri() + WebConstants.PATH_SEP + id;
return findOneByUriAsResponse(uriOfResource, req);
}
@Override
public final T findOneByUri(final String uriOfResource) {
final String resourceAsMime = findOneByUriAsString(uriOfResource);
return marshaller.decode(resourceAsMime, clazz);
}
protected final String findOneByUriAsString(final String uriOfResource) {
final Response response = findOneByUriAsResponse(uriOfResource);
Preconditions.checkState(response.getStatusCode() == 200);
return response.asString();
}
protected final String findOneByUriAsString(final String uriOfResource, final RequestSpecification req) {
final Response response = findOneByUriAsResponse(uriOfResource, req);
Preconditions.checkState(response.getStatusCode() == 200);
return response.asString();
}
final Response findOneByUriAsResponse(final String uriOfResource) {
return findOneByUriAsResponse(uriOfResource, null);
}
@Override
public final Response findOneByUriAsResponse(final String uriOfResource, final RequestSpecification req) {
if (req == null) {
return readRequest().get(uriOfResource);
}
return readRequest(req).get(uriOfResource);
}
// find - all
final Response findAllByUriAsResponse(final String uriOfResource, final RequestSpecification req) {
if (req == null) {
return readExtendedRequest().get(uriOfResource);
}
return readExtendedRequest(req).get(uriOfResource);
}
final Response findAllByUriAsResponse(final String uriOfResource) {
return findAllByUriAsResponse(uriOfResource, null);
}
@Override
public List<T> findAll() {
return findAllByUri(getUri());
}
@Override
public final List<T> findAllByUri(final String uri) {
final Response allAsResponse = readExtendedRequest().get(uri);
final List<T> listOfResources = marshaller.<T> decodeList(allAsResponse.getBody().asString(), clazz);
if (listOfResources == null) {
return Lists.newArrayList();
}
return listOfResources;
}
public final Response findAllAsResponse() {
return findAllAsResponse(null);
}
@Override
public final Response findAllAsResponse(final RequestSpecification req) {
return findAllByUriAsResponse(getUri(), req);
}
// find - all (sorted, paginated)
@Override
public final List<T> findAllSorted(final String sortBy, final String sortOrder) {
final Response findAllResponse = findAllByUriAsResponse(getUri() + QueryConstants.Q_SORT_BY + sortBy + QueryConstants.S_ORDER + sortOrder);
return marshaller.<T> decodeList(findAllResponse.getBody().asString(), clazz);
}
@Override
public final List<T> findAllPaginated(final int page, final int size) {
final Response allPaginatedAsResponse = findAllPaginatedAsResponse(page, size);
return getMarshaller().decodeList(allPaginatedAsResponse.asString(), clazz);
}
@Override
public final List<T> findAllPaginatedAndSorted(final int page, final int size, final String sortBy, final String sortOrder) {
final Response allPaginatedAndSortedAsResponse = findAllPaginatedAndSortedAsResponse(page, size, sortBy, sortOrder);
return getMarshaller().decodeList(allPaginatedAndSortedAsResponse.asString(), clazz);
}
@Override
public final Response findAllPaginatedAndSortedAsResponse(final int page, final int size, final String sortBy, final String sortOrder) {
return findAllPaginatedAndSortedAsResponse(page, size, sortBy, sortOrder, null);
}
final Response findAllPaginatedAndSortedAsResponse(final int page, final int size, final String sortBy, final String sortOrder, final RequestSpecification req) {
final StringBuilder uri = new StringBuilder(getUri());
uri.append(QueryConstants.QUESTIONMARK);
uri.append("page=");
uri.append(page);
uri.append(QueryConstants.SEPARATOR_AMPER);
uri.append("size=");
uri.append(size);
Preconditions.checkState(!(sortBy == null && sortOrder != null));
if (sortBy != null) {
uri.append(QueryConstants.SEPARATOR_AMPER);
uri.append(QueryConstants.SORT_BY + "=");
uri.append(sortBy);
}
if (sortOrder != null) {
uri.append(QueryConstants.SEPARATOR_AMPER);
uri.append(QueryConstants.SORT_ORDER + "=");
uri.append(sortOrder);
}
return findAllByUriAsResponse(uri.toString(), req);
}
@Override
public final Response findAllSortedAsResponse(final String sortBy, final String sortOrder) {
return findAllSortedAsResponse(sortBy, sortOrder, null);
}
final Response findAllSortedAsResponse(final String sortBy, final String sortOrder, final RequestSpecification req) {
final StringBuilder uri = new StringBuilder(getUri());
uri.append(QueryConstants.QUESTIONMARK);
Preconditions.checkState(!(sortBy == null && sortOrder != null));
if (sortBy != null) {
uri.append(QueryConstants.SORT_BY + "=");
uri.append(sortBy);
}
if (sortOrder != null) {
uri.append(QueryConstants.SEPARATOR_AMPER);
uri.append(QueryConstants.SORT_ORDER + "=");
uri.append(sortOrder);
}
return findAllByUriAsResponse(uri.toString(), req);
}
@Override
public final Response findAllPaginatedAsResponse(final int page, final int size) {
return findAllPaginatedAsResponse(page, size, null);
}
final Response findAllPaginatedAsResponse(final int page, final int size, final RequestSpecification req) {
final StringBuilder uri = new StringBuilder(getUri());
uri.append(QueryConstants.QUESTIONMARK);
uri.append("page=");
uri.append(page);
uri.append(QueryConstants.SEPARATOR_AMPER);
uri.append("size=");
uri.append(size);
return findAllByUriAsResponse(uri.toString(), req);
}
// create
@Override
public final T create(final T resource) {
final String uriForResourceCreation = createAsUri(resource);
final String resourceAsMime = findOneByUriAsString(uriForResourceCreation);
return marshaller.decode(resourceAsMime, clazz);
}
@Override
public final String createAsUri(final T resource) {
return createAsUri(resource, null);
}
final String createAsUri(final T resource, final Pair<String, String> credentials) {
final Response response = createAsResponse(resource, credentials);
Preconditions.checkState(response.getStatusCode() == 201, "create operation: " + response.getStatusCode());
final String locationOfCreatedResource = response.getHeader(HttpHeaders.LOCATION);
Preconditions.checkNotNull(locationOfCreatedResource);
return locationOfCreatedResource;
}
@Override
public final Response createAsResponse(final T resource) {
return createAsResponse(resource, null);
}
@Override
public final Response createAsResponse(final T resource, final Pair<String, String> credentials) {
Preconditions.checkNotNull(resource);
RequestSpecification givenAuthenticated = null;
if (credentials != null) {
givenAuthenticated = auth.givenBasicAuthenticated(credentials.getLeft(), credentials.getRight());
} else {
givenAuthenticated = givenWriteAuthenticated();
}
final String resourceAsString = marshaller.encode(resource);
logger.debug("Creating Resource against URI: " + getUri());
return givenAuthenticated.contentType(marshaller.getMime()).body(resourceAsString).post(getUri());
}
// update
@Override
public final void update(final T resource) {
final Response updateResponse = updateAsResponse(resource);
Preconditions.checkState(updateResponse.getStatusCode() == 200, "Update Operation: " + updateResponse.getStatusCode());
}
@Override
public final Response updateAsResponse(final T resource) {
Preconditions.checkNotNull(resource);
final String resourceAsString = marshaller.encode(resource);
return givenWriteAuthenticated().contentType(marshaller.getMime()).body(resourceAsString).put(getUri() + "/" + resource.getId());
}
// delete
@Override
public final void deleteAll() {
throw new UnsupportedOperationException();
}
@Override
public final void delete(final long id) {
final Response deleteResponse = deleteAsResponse(id);
Preconditions.checkState(deleteResponse.getStatusCode() == 204);
}
@Override
public final Response deleteAsResponse(final long id) {
return givenDeleteAuthenticated().delete(getUri() + WebConstants.PATH_SEP + id);
}
// search - as response
@Override
public final Response searchAsResponse(final Triple<String, ClientOperation, String> idOp, final Triple<String, ClientOperation, String> nameOp) {
final String queryURI = getUri() + QueryConstants.QUERY_PREFIX + SearchTestUtil.constructQueryString(idOp, nameOp);
return readExtendedRequest().get(queryURI);
}
@Override
public final Response searchAsResponse(final Triple<String, ClientOperation, String> idOp, final Triple<String, ClientOperation, String> nameOp, final int page, final int size) {
final String queryURI = getUri() + QueryConstants.QUERY_PREFIX + SearchTestUtil.constructQueryString(idOp, nameOp) + "&page=" + page + "&size=" + size;
return readExtendedRequest().get(queryURI);
}
// search
@Override
public final List<T> searchAll(final Triple<String, ClientOperation, String>... constraints) {
final Response searchResponse = searchAsResponse(constraints);
return getMarshaller().<T> decodeList(searchResponse.getBody().asString(), clazz);
}
@Override
public final T searchOne(final Triple<String, ClientOperation, String>... constraints) {
final List<T> all = searchAll(constraints);
if (all.isEmpty()) {
return null;
}
Preconditions.checkState(all.size() <= 1);
return all.get(0);
}
@Override
public final Response searchAsResponse(final Triple<String, ClientOperation, String>... constraints) {
final SearchUriBuilder builder = new SearchUriBuilder();
for (final Triple<String, ClientOperation, String> constraint : constraints) {
builder.consume(constraint);
}
final String queryURI = getUri() + QueryConstants.QUERY_PREFIX + builder.build();
final Response searchResponse = readExtendedRequest().get(queryURI);
Preconditions.checkState(searchResponse.getStatusCode() == 200, "Search is = " + searchResponse.getStatusCode());
return searchResponse;
}
@Override
public final List<T> searchPaginated(final Triple<String, ClientOperation, String> idOp, final Triple<String, ClientOperation, String> nameOp, final int page, final int size) {
final String queryURI = getUri() + QueryConstants.QUERY_PREFIX + SearchTestUtil.constructQueryString(idOp, nameOp) + "&page=" + page + "&size=" + size;
final Response searchResponse = readExtendedRequest().get(queryURI);
Preconditions.checkState(searchResponse.getStatusCode() == 200, "Search is = " + searchResponse.getStatusCode());
return getMarshaller().<List> decode(searchResponse.getBody().asString(), List.class);
}
// count
@Override
public long count() {
return Long.valueOf(countAsResponse().asString());
}
@Override
public final Response countAsResponse() {
return givenReadAuthenticated().get(getUri() + "/count");
}
// API - other
@Override
public final Response read(final String uriOfResource) {
return readRequest().get(uriOfResource);
}
private final RequestSpecification readRequest(final RequestSpecification req) {
return req.header(HttpHeaders.ACCEPT, marshaller.getMime());
}
protected final RequestSpecification readRequest() {
return givenReadAuthenticated().header(HttpHeaders.ACCEPT, marshaller.getMime());
}
protected final RequestSpecification readExtendedRequest(final RequestSpecification req) {
return req.header(HttpHeaders.ACCEPT, marshaller.getMime());
}
protected final RequestSpecification readExtendedRequest() {
return givenReadExtendedAuthenticated().header(HttpHeaders.ACCEPT, marshaller.getMime());
}
// security
@Override
public final RequestSpecification givenReadAuthenticated() {
final Pair<String, String> credentials = getReadCredentials();
return auth.givenBasicAuthenticated(credentials.getLeft(), credentials.getRight());
}
final RequestSpecification givenReadExtendedAuthenticated() {
final Pair<String, String> credentials = getReadExtendedCredentials();
return auth.givenBasicAuthenticated(credentials.getLeft(), credentials.getRight());
}
final RequestSpecification givenWriteAuthenticated() {
final Pair<String, String> credentials = getWriteCredentials();
return auth.givenBasicAuthenticated(credentials.getLeft(), credentials.getRight());
}
@Override
public final RequestSpecification givenDeleteAuthenticated() {
final Pair<String, String> credentials = getWriteCredentials();
return auth.givenBasicAuthenticated(credentials.getLeft(), credentials.getRight());
}
protected Pair<String, String> getWriteCredentials() {
return getDefaultCredentials();
}
protected Pair<String, String> getDeleteCredentials() {
return getWriteCredentials();
}
Pair<String, String> getReadCredentials() {
return getDefaultCredentials();
}
protected Pair<String, String> getReadExtendedCredentials() {
return getReadCredentials();
}
protected abstract Pair<String, String> getDefaultCredentials();
/**
* - this is a hook that executes before read operations, in order to allow custom security work to happen for read operations; similar to: AbstractRestTemplate.findRequest
*/
protected void beforeReadOperation() {
//
}
//
@Override
public final IMarshaller getMarshaller() {
return marshaller;
}
}