com.nesscomputing.httpclient.testing.JaxRsResponseHttpResponseGenerator.java Source code

Java tutorial

Introduction

Here is the source code for com.nesscomputing.httpclient.testing.JaxRsResponseHttpResponseGenerator.java

Source

/**
 * Copyright (C) 2012 Ness Computing, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.nesscomputing.httpclient.testing;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
import com.google.common.base.Functions;
import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import org.apache.commons.lang3.ObjectUtils;

import com.nesscomputing.httpclient.HttpClientRequest;
import com.nesscomputing.httpclient.HttpClientResponse;

/**
 * An all-purpose {@link ResponseGenerator} which supports converting JAX-RS {@link Response}
 * objects into the actual {@link HttpClientResponse} that you might expect to see.
 * <p>Supported entity formats include:
 * <ul>
 * <li> Null: empty <code>text/plain</code> response
 * <li> String: <code>text/plain</code> response
 * <li> Byte array: <code>application/octet-stream</code> response
 * <li> Object: <code>application/json</code> response generated via Jackson's {@link ObjectMapper}
 * </ul>
 * The above Content-Type is set unless the Response already has one, which always takes precedence.
 * The Content-Length header is always present.  The charset is always <code>UTF-8</code>.
 */
@Immutable
public class JaxRsResponseHttpResponseGenerator implements ResponseGenerator<Object> {
    private final Response response;
    private final InputStream responseBody;
    private final MediaType contentType;
    private final long contentLength;
    private final String charset;

    /**
     * Create a new response generator
     * @param mapper Jackson mapper for converting entities to JSON, may be null.  Attempts to
     * serialize to JSON with a null mapper will fail spectacularly.
     * @param response The response to send back on fetches.
     */
    public JaxRsResponseHttpResponseGenerator(@Nullable ObjectMapper mapper, Response response) {
        this.response = response;
        Object entity = response.getEntity();
        charset = Charsets.UTF_8.name();
        MediaType contentTypeIn = null;
        List<Object> typeHeaders = response.getMetadata().get("Content-Type");
        if (typeHeaders == null) { // Damn you to hell, people who reinvent Multimap poorly!
            typeHeaders = Collections.emptyList();
        }
        Preconditions.checkArgument(typeHeaders.size() <= 1, "multiple Content-Type headers?!");
        final byte[] encoded;
        if (!typeHeaders.isEmpty()) {
            contentTypeIn = MediaType.valueOf(typeHeaders.get(0).toString());
        }
        if (entity == null) {
            if (contentTypeIn == null) {
                contentTypeIn = MediaType.TEXT_PLAIN_TYPE;
            }
            encoded = new byte[0];
        } else if (entity instanceof String) {
            if (contentTypeIn == null) {
                contentTypeIn = MediaType.TEXT_PLAIN_TYPE;
            }
            encoded = ((String) entity).getBytes(Charsets.UTF_8);
        } else if (entity instanceof byte[]) {
            if (contentTypeIn == null) {
                contentTypeIn = MediaType.APPLICATION_OCTET_STREAM_TYPE;
            }
            encoded = (byte[]) entity;
        } else {
            Preconditions.checkNotNull(mapper, "Mapper null and unknown type " + entity.getClass() + " provided");
            if (contentTypeIn == null) {
                contentTypeIn = MediaType.APPLICATION_JSON_TYPE;
            }
            try {
                encoded = mapper.writeValueAsBytes(entity);
            } catch (IOException e) {
                throw new IllegalStateException(e);
            }
        }
        responseBody = new ByteArrayInputStream(encoded);
        contentLength = encoded.length;
        this.contentType = contentTypeIn;
    }

    @Override
    public HttpClientResponse respondTo(final HttpClientRequest<Object> request) {
        return new HttpClientResponse() {
            @Override
            public int getStatusCode() {
                return response.getStatus();
            }

            @Override
            public String getStatusText() {
                return Status.fromStatusCode(getStatusCode()).getReasonPhrase();
            }

            @Override
            public InputStream getResponseBodyAsStream() throws IOException {
                return responseBody;
            }

            @Override
            public URI getUri() {
                return request.getUri();
            }

            @Override
            public String getContentType() {
                return ObjectUtils.toString(contentType, null);
            }

            @Override
            public Long getContentLength() {
                return contentLength;
            }

            @Override
            public String getCharset() {
                return charset;
            }

            @Override
            public String getHeader(String name) {
                List<Object> headers = response.getMetadata().get(name);
                if (headers == null || headers.isEmpty()) {
                    return null;
                }
                return headers.get(0).toString();
            }

            @Override
            public List<String> getHeaders(String name) {
                List<Object> headers = response.getMetadata().get(name);
                if (headers == null) {
                    return null;
                }
                return ImmutableList.copyOf(Collections2.transform(headers, Functions.toStringFunction()));
            }

            @Override
            public Map<String, List<String>> getAllHeaders() {
                ImmutableMap.Builder<String, List<String>> result = ImmutableMap.builder();
                for (Entry<String, List<Object>> e : response.getMetadata().entrySet()) {
                    result.put(e.getKey(), ImmutableList
                            .copyOf(Collections2.transform(e.getValue(), Functions.toStringFunction())));
                }
                return result.build();
            }

            @Override
            public boolean isRedirected() {
                return false;
            }
        };
    }

    @Override
    public String toString() {
        return String.format(
                "JaxRsResponseHttpResponseGenerator"
                        + " [status=%d %s, contentType=%s, contentLength=%s, charset=%s]",
                response.getStatus(), Status.fromStatusCode(response.getStatus()).getReasonPhrase(), contentType,
                contentLength, charset);
    }
}