package com.github.kristofa.test.http; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; public class HttpRequestImpl implements HttpRequest { private static final String NOT_SPECIFIED = "null"; private Method method; private ContentMatcher contentMatcher; private String path; private final Set<QueryParameter> queryParameters = new TreeSet<QueryParameter>(); private final Set<HttpMessageHeader> httpMessageHeaders = new TreeSet<HttpMessageHeader>(); /** * Creates a new unintialized instance. */ public HttpRequestImpl() { contentMatcher = new DefaultContentMatcher(); } /** * Copy constructor. Will initialize http request with content of given request. * * @param request Request to copy. */ public HttpRequestImpl(final HttpRequest request) { if (request instanceof HttpRequestImpl) { final ContentMatcher otherMatcher = ((HttpRequestImpl)request).contentMatcher; if (otherMatcher != null) { contentMatcher = otherMatcher.copy(); } } else { contentMatcher = new DefaultContentMatcher(); try { contentMatcher.setContent(request.getContent()); } catch (final UnexpectedContentException e) { throw new IllegalStateException(e); } } method = request.getMethod(); path = request.getPath(); for (final HttpMessageHeader header : request.getHttpMessageHeaders()) { httpMessageHeaders.add(new HttpMessageHeader(header.getName(), header.getValue())); } for (final QueryParameter parameter : request.getQueryParameters()) { queryParameters.add(new QueryParameter(parameter.getKey(), parameter.getValue())); } } /** * Sets method for request. * * @param method Method for request. * @return This http request. */ public HttpRequestImpl method(final Method method) { this.method = method; return this; } /** * Sets content of message body for request. * * @param content Message body for request. * @return This http request. */ public HttpRequestImpl content(final byte[] content) { try { contentMatcher.setContent(content); } catch (final UnexpectedContentException e) { throw new IllegalStateException(e); } return this; } /** * Sets {@link ContentMatcher}. It will be initialized with any existing data. * <p/> * If not set a default {@link ContentMatcher} will be used which simply does an equals on byte array. * * @param matcher New Content matcher. Should not be <code>null</code>. * @return This http request. * @throws UnexpectedContentException In case the current content is incompatible with the new ContentMatcher. In this * case the new matcher will not be set. The previous {@link ContentMatcher} will remain active. */ public HttpRequestImpl contentMatcher(final ContentMatcher matcher) throws UnexpectedContentException { Validate.notNull(matcher); final byte[] content = contentMatcher.getContent(); if (content != null) { matcher.setContent(content); contentMatcher = matcher; } else { contentMatcher = matcher; } return this; } /** * Sets path for request. * * @param path Sets path for request. * @return This http request. */ public HttpRequestImpl path(final String path) { this.path = path; return this; } /** * Adds a query parameter for request. * * @param key Parameter key. Should not be empty or <code>null</code> or blank. * @param value Parameter value. Should not be empty or <code>null</code> or blank. * @return This http request. */ public HttpRequestImpl queryParameter(final String key, final String value) { queryParameters.add(new QueryParameter(key, value)); return this; } /** * Removes Query Parameter with given key and value. * * @param key Query parameter key. * @param value Query parameter value. * @return This http request. */ public HttpRequestImpl removeQueryParameter(final String key, final String value) { queryParameters.remove(new QueryParameter(key, value)); return this; } /** * Removes all Query Parameters that have given key. * * @param key Query parameter key. * @return This http request. */ public HttpRequestImpl removeQueryParameters(final String key) { final Set<QueryParameter> toRemove = new HashSet<QueryParameter>(); for (final QueryParameter qp : queryParameters) { if (qp.getKey().equals(key)) { toRemove.add(qp); } } queryParameters.removeAll(toRemove); return this; } /** * Adds a Http message header. * * @param name header name. Should not be <code>null</code> or blank. * @param value header value. Should not be <code>null</code> or blank. * @return This http request. */ public HttpRequestImpl httpMessageHeader(final String name, final String value) { httpMessageHeaders.add(new HttpMessageHeader(name, value)); return this; } /** * Removes Http message header with given name and value. * * @param name Http message header name. * @param value Http message header value. * @return This http request. */ public HttpRequestImpl removeHttpMessageHeader(final String name, final String value) { httpMessageHeaders.remove(new HttpMessageHeader(name, value)); return this; } /** * Removes all Http message headers with given name. * * @param name Http message header name. * @return This http request. */ public HttpRequestImpl removeHttpMessageHeaders(final String name) { final Set<HttpMessageHeader> toRemove = new HashSet<HttpMessageHeader>(); for (final HttpMessageHeader header : httpMessageHeaders) { if (header.getName().equals(name)) { toRemove.add(header); } } httpMessageHeaders.removeAll(toRemove); return this; } /** * {@inheritDoc} */ @Override public Method getMethod() { return method; } /** * {@inheritDoc} */ @Override public byte[] getContent() { if (contentMatcher == null) { return null; } final byte[] content = contentMatcher.getContent(); if (content == null) { return null; } return Arrays.copyOf(content, content.length); } /** * {@inheritDoc} */ @Override public String getPath() { return path; } /** * {@inheritDoc} */ @Override public Set<QueryParameter> getQueryParameters() { return Collections.unmodifiableSet(queryParameters); } /** * {@inheritDoc} */ @Override public Set<HttpMessageHeader> getHttpMessageHeaders() { return Collections.unmodifiableSet(httpMessageHeaders); } /** * {@inheritDoc} */ @Override public Set<QueryParameter> getQueryParameters(final String key) { Validate.notBlank(key); final Set<QueryParameter> qpSubset = new TreeSet<QueryParameter>(); for (final QueryParameter qp : queryParameters) { if (qp.getKey().equals(key)) { qpSubset.add(qp); } } return qpSubset; } /** * {@inheritDoc} */ @Override public Set<HttpMessageHeader> getHttpMessageHeaders(final String name) { Validate.notBlank(name); final Set<HttpMessageHeader> mhSubset = new TreeSet<HttpMessageHeader>(); for (final HttpMessageHeader header : httpMessageHeaders) { if (header.getName().equals(name)) { mhSubset.add(header); } } return mhSubset; } /** * {@inheritDoc} */ @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this, false); } /** * {@inheritDoc} */ @Override public boolean equals(final Object obj) { return EqualsBuilder.reflectionEquals(this, obj, false); } @Override public String toString() { final String methodString = add("Method: ", getMethod()); final String messageHeaderString = add("Message Header: ", getHttpMessageHeaders()); final String pathString = add("Path: ", getPath()); final String queryParamsString = add("Query Parameters: ", getQueryParameters()); String contentString = null; if (getContent() == null) { contentString = add("Content:\n", getContent()); } else { contentString = add("Content:\n", new String(getContent())); } final String[] array = {methodString, messageHeaderString, pathString, queryParamsString, contentString}; return StringUtils.join(array, "\n"); } private String add(final String value, final Object object) { if (object != null) { return value + object; } return value + NOT_SPECIFIED; } }