com.dynatrace.openkit.protocol.Response Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openkit-java Show documentation
Show all versions of openkit-java Show documentation
Dynatrace OpenKit - Java Reference Implementation
/**
* Copyright 2018-2019 Dynatrace LLC
*
* 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.dynatrace.openkit.protocol;
import com.dynatrace.openkit.api.Logger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
* Abstract base class for a response to one of the 3 request types (status check, beacon send, time sync).
*/
public abstract class Response {
static class KeyValuePair {
final String key;
final String value;
KeyValuePair(String key, String value) {
this.key = key;
this.value = value;
}
}
/**
* Response code sent by HTTP server to indicate success.
*/
public static final int HTTP_OK = 200;
/**
* Bad request is error code 400 in the HTTP protocol.
*/
public static final int HTTP_BAD_REQUEST = 400;
/**
* Too many requests sent by client (rate limiting) error code.
*/
public static final int HTTP_TOO_MANY_REQUESTS = 429;
/**
* Key in the HTTP response headers for Retry-After
*/
static final String RESPONSE_KEY_RETRY_AFTER = "retry-after";
/**
* Default "Retry-After" is 10 minutes.
*/
static final long DEFAULT_RETRY_AFTER_IN_MILLISECONDS = 10L * 60L * 1000L;
private final Logger logger;
private final int responseCode;
private final Map> headers;
// *** constructors ***
Response(Logger logger, int responseCode, Map> headers) {
this.logger = logger;
this.responseCode = responseCode;
this.headers = responseHeadersWithLowerCaseKeys(headers);
}
private static Map> responseHeadersWithLowerCaseKeys(Map> headers) {
Map> result = new HashMap>(headers.size());
for (Map.Entry> entry : headers.entrySet()) {
if (entry.getKey() != null && entry.getValue() != null) {
result.put(entry.getKey().toLowerCase(), entry.getValue());
}
}
return Collections.unmodifiableMap(result);
}
// *** getter methods ***
public boolean isErroneousResponse() {
return getResponseCode() >= HTTP_BAD_REQUEST;
}
public int getResponseCode() {
return responseCode;
}
public Map> getHeaders() {
return headers;
}
public long getRetryAfterInMilliseconds() {
List values = getHeaders().get(RESPONSE_KEY_RETRY_AFTER);
if (values == null) {
// the Retry-After response header is missing
logger.warning(RESPONSE_KEY_RETRY_AFTER + " is not available - using default value " + DEFAULT_RETRY_AFTER_IN_MILLISECONDS);
return DEFAULT_RETRY_AFTER_IN_MILLISECONDS;
}
if (values.size() != 1) {
// the Retry-After response header has multiple values, but only one is expected
logger.warning(RESPONSE_KEY_RETRY_AFTER + " has unexpected number of values - using default value " + DEFAULT_RETRY_AFTER_IN_MILLISECONDS);
return DEFAULT_RETRY_AFTER_IN_MILLISECONDS;
}
// according to RFC 7231 Section 7.1.3 (https://tools.ietf.org/html/rfc7231#section-7.1.3)
// Retry-After value can either be a delay seconds value, which is a non-negative decimal integer
// or it is an HTTP date.
// Our implementation assumes only delay seconds value here
int delaySeconds;
try {
delaySeconds = Integer.parseInt(values.get(0));
} catch (NumberFormatException e) {
logger.error("Failed to parse " + RESPONSE_KEY_RETRY_AFTER + " value \"" + values.get(0)
+ "\" - using default value " + DEFAULT_RETRY_AFTER_IN_MILLISECONDS);
return DEFAULT_RETRY_AFTER_IN_MILLISECONDS;
}
// convert delay seconds to milliseconds
return delaySeconds * 1000L;
}
static List parseResponseKeyValuePair(String response) {
List result = new ArrayList();
StringTokenizer tokenizer = new StringTokenizer(response, "&");
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
int keyValueSeparatorIndex = token.indexOf('=');
if (keyValueSeparatorIndex == -1) {
throw new IllegalArgumentException("Invalid response; even number of tokens expected.");
}
String key = token.substring(0, keyValueSeparatorIndex);
String value = token.substring(keyValueSeparatorIndex + 1);
result.add(new KeyValuePair(key, value));
}
return result;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy