com.couchbase.client.core.error.ErrorCodeAndMessage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-io Show documentation
Show all versions of core-io Show documentation
The official Couchbase JVM Core IO Library
/*
* Copyright 2019 Couchbase, 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.couchbase.client.core.error;
import com.couchbase.client.core.annotation.Stability;
import com.couchbase.client.core.deps.com.fasterxml.jackson.annotation.JsonAnySetter;
import com.couchbase.client.core.deps.com.fasterxml.jackson.annotation.JsonProperty;
import com.couchbase.client.core.deps.com.fasterxml.jackson.core.type.TypeReference;
import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.JsonNode;
import com.couchbase.client.core.json.Mapper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.couchbase.client.core.util.CbCollections.listOf;
import static com.couchbase.client.core.util.CbStrings.nullToEmpty;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
/**
* A numeric error code and associated human-readable error message.
*/
public class ErrorCodeAndMessage {
private final int code;
private final String message;
private final boolean retry;
private final Map reason;
// Jackson adds unrecognized properties here. An example is the "query_from_user" field
// that appears in some query errors.
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@JsonAnySetter
private final Map context = new HashMap<>();
public ErrorCodeAndMessage(@JsonProperty("code") int code,
@JsonProperty("msg") String message,
@JsonProperty("retry") boolean retry,
@JsonProperty("reason") Map reason) {
this.code = code;
this.message = nullToEmpty(message);
this.retry = retry;
this.reason = reason;
}
public int code() {
return code;
}
public String message() {
return message;
}
public boolean retry() {
return retry;
}
public Map reason() {
return reason;
}
/**
* Returns an unmodifiable map of any additional information returned by the server.
*/
public Map context() {
return unmodifiableMap(context);
}
@Override
public String toString() {
return code + " " + message + (!context.isEmpty() ? " Context: " + context : "");
}
@Stability.Internal
public static List fromJsonArray(byte[] jsonArray) {
return from(jsonArray);
}
private static final Pattern plaintextErrorPattern = Pattern.compile("(?\\d+):(?.+)");
private static List fromPlaintext(byte[] errorBytes) {
String error = new String(errorBytes, UTF_8).trim();
error = translateLegacyAnalyticsErrorCodes(error);
Matcher m = plaintextErrorPattern.matcher(error);
if (m.matches()) {
return listOf(new ErrorCodeAndMessage(Integer.parseInt(m.group("errorCode")), m.group("message"), false, null));
}
return listOf(new ErrorCodeAndMessage(0, "Failed to decode error: " + error, false, null));
}
private static String translateLegacyAnalyticsErrorCodes(String error) {
// Before 7.0 the analytics service returned non-numeric error codes
// in link management API responses. Let's translate the ones we care about!
if (error.startsWith("CBAS") || error.startsWith("ASX")) {
return error
.replace("CBAS0026", "24055") // link already exists
.replace("CBAS0027", "24006") // link not found
.replace("ASX1063", "24034") // dataverse not found
// 24001 is arbitrary... just needs to be in the 24xxx range and not mapped to another exception type
.replace("CBAS0062", "24001") // invalid argument (missing parameter)
.replace("CBAS0063", "24001") // invalid argument (unexpected parameter)
;
}
return error;
}
@Stability.Internal
public static List from(byte[] content) {
JsonNode node;
try {
node = Mapper.decodeIntoTree(content);
} catch (Exception notJson) {
return fromPlaintext(content);
}
try {
if (node.isArray()) {
return unmodifiableList(Mapper.convertValue(node, new TypeReference>() {
}));
}
if (node.isObject()) {
return listOf(Mapper.convertValue(node, ErrorCodeAndMessage.class));
}
} catch (Exception malformed) {
// fall through
}
return listOf(new ErrorCodeAndMessage(0, "Failed to decode errors: " + new String(content, UTF_8), false, null));
}
}