/*
* Copyright (C) 2014 SCVNGR, Inc. d/b/a LevelUp
*
* 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.scvngr.levelup.core.net;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.scvngr.levelup.core.annotation.LevelUpApi;
import com.scvngr.levelup.core.annotation.LevelUpApi.Contract;
import com.scvngr.levelup.core.annotation.VisibleForTesting;
import com.scvngr.levelup.core.annotation.VisibleForTesting.Visibility;
import net.jcip.annotations.NotThreadSafe;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Map;
/**
* Object which represents an HTTP response.
*
* @param <T> the response data type.
*/
@NotThreadSafe
@LevelUpApi(contract = Contract.DRAFT)
public abstract class AbstractResponse<T> {
/**
* Sentinel status code when no HTTP status code was received.
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
/* package */static final int HTTP_STATUS_CODE_UNUSED = -1;
/**
* The minimum HTTP response code from the server considered to be OK.
*/
/* package */static final int STATUS_CODE_SUCCESS_MIN_INCLUSIVE = HttpURLConnection.HTTP_OK;
/**
* The maximum HTTP response code from the server considered to be OK.
*/
/* package */static final int STATUS_CODE_SUCCESS_MAX_EXCLUSIVE =
HttpURLConnection.HTTP_MULT_CHOICE;
/**
* the HTTP status code of the response.
*/
private final int mHttpStatusCode;
/**
* any exception that was thrown during the request or null if there was none.
*/
@Nullable
private final Exception mError;
/**
* The HTTP headers.
*/
@Nullable
private final Map<String, List<String>> mHttpHeaders;
/**
* Constructor for an error response.
*
* @param error any exception that was thrown during the request.
*/
protected AbstractResponse(@NonNull final Exception error) {
this(HTTP_STATUS_CODE_UNUSED, error);
}
/**
* Default constructor for testing.
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
/* package */AbstractResponse() {
this(HTTP_STATUS_CODE_UNUSED, null);
}
/**
* @param statusCode the HTTP status code.
* @param error the {@link Exception} that was thrown during the request or {@code null} if
* there was no error.
*/
protected AbstractResponse(final int statusCode, @Nullable final Exception error) {
mHttpStatusCode = statusCode;
mError = error;
mHttpHeaders = null;
}
/**
* @param statusCode the HTTP status code of the response.
* @param httpHeaders the HTTP headers included in the response. This must be an unmodifiable
* map, for example one wrapped using {@link java.util.Collections#unmodifiableMap(Map)}.
* @param error the {@link Exception} that was thrown during the request or {@code null} if
* there was no error.
*/
protected AbstractResponse(final int statusCode,
@Nullable final Map<String, List<String>> httpHeaders, @Nullable final Exception error) {
mHttpStatusCode = statusCode;
mError = error;
mHttpHeaders = httpHeaders;
}
/**
* @return the data sent from the server in this response.
*/
@Nullable
public abstract T getData();
/**
* @return HTTP status code passed back from the server (if any).
*/
public final int getHttpStatusCode() {
return mHttpStatusCode;
}
/**
* Retrieves the desired HTTP header. If multiple headers of the same key are present, this
* retrieves the first one.
*
* @param headerField the HTTP header field (the key). This value must be be normalized to
* First-Letter-Caps.
* @return the value of the header or {@code null} if no header is present.
*/
@Nullable
public final String getHttpHeader(@NonNull final String headerField) {
String result = null;
if (null != mHttpHeaders) {
final List<String> values = mHttpHeaders.get(headerField);
if (null != values && 0 != values.size()) {
result = values.get(0);
}
}
return result;
}
/**
* @return the HTTP headers.
*/
protected Map<String, List<String>> getHttpHeaders() {
return mHttpHeaders;
}
/**
* @return the {@link Exception} that was thrown during a request.
*/
@Nullable
public Exception getError() {
return mError;
}
@Override
public String toString() {
// CHECKSTYLE:OFF long format string
return String.format("AbstractResponse [mHttpStatusCode=%s, mError=%s]", mHttpStatusCode,
mError);
// CHECKSTYLE:ON
}
}