/*
* Copyright (C) 2012-2015 DataStax 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.datastax.driver.core.exceptions;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
/**
* Exception thrown when a query cannot be performed because no host is
* available.
* <p/>
* This exception is thrown if either:
* <ul>
* <li>there is no host live in the cluster at the moment of the query;</li>
* <li>all hosts that have been tried have failed.</li>
* </ul>
* <p/>
* For debugging purposes, the list of hosts that have been tried along with the
* failure cause can be retrieved using the {@link #getErrors()} method.
*/
public class NoHostAvailableException extends DriverException {
private static final long serialVersionUID = 0;
private static final int MAX_ERRORS_IN_DEFAULT_MESSAGE = 3;
private final Map<InetSocketAddress, Throwable> errors;
public NoHostAvailableException(Map<InetSocketAddress, Throwable> errors) {
super(makeMessage(errors, MAX_ERRORS_IN_DEFAULT_MESSAGE, false, false));
this.errors = errors;
}
private NoHostAvailableException(String message, Throwable cause, Map<InetSocketAddress, Throwable> errors) {
super(message, cause);
this.errors = errors;
}
/**
* Return the hosts tried along with the error encountered while trying
* them.
*
* @return a map containing for each tried host the error triggered when
* trying it.
*/
public Map<InetSocketAddress, Throwable> getErrors() {
return new HashMap<InetSocketAddress, Throwable>(errors);
}
/**
* Builds a custom message for this exception.
*
* @param maxErrors the maximum number of errors displayed (useful to limit the size of the message for big clusters). Beyond this limit,
* host names are still displayed, but not the associated errors. Set to {@code Integer.MAX_VALUE} to display all hosts.
* @param formatted whether to format the output (line break between each host).
* @param includeStackTraces whether to include the full stacktrace of each host error. Note that this automatically implies
* {@code formatted}.
* @return the message.
*/
public String getCustomMessage(int maxErrors, boolean formatted, boolean includeStackTraces) {
if (includeStackTraces)
formatted = true;
return makeMessage(errors, maxErrors, formatted, includeStackTraces);
}
@Override
public NoHostAvailableException copy() {
return new NoHostAvailableException(getMessage(), this, errors);
}
private static String makeMessage(Map<InetSocketAddress, Throwable> errors, int maxErrorsInMessage, boolean formatted, boolean includeStackTraces) {
if (errors.size() == 0)
return "All host(s) tried for query failed (no host was tried)";
StringWriter stringWriter = new StringWriter();
PrintWriter out = new PrintWriter(stringWriter);
out.print("All host(s) tried for query failed (tried:");
out.print(formatted ? "\n" : " ");
int n = 0;
boolean truncated = false;
for (Map.Entry<InetSocketAddress, Throwable> entry : errors.entrySet()) {
if (n > 0) out.print(formatted ? "\n" : ", ");
out.print(entry.getKey());
if (n < maxErrorsInMessage) {
if (includeStackTraces) {
out.print("\n");
entry.getValue().printStackTrace(out);
out.print("\n");
} else {
out.printf(" (%s)", entry.getValue());
}
} else {
truncated = true;
}
n += 1;
}
if (truncated) {
out.print(formatted ? "\n" : " ");
out.printf("[only showing errors of first %d hosts, use getErrors() for more details]", maxErrorsInMessage);
}
if (formatted && !includeStackTraces)
out.print("\n");
out.print(")");
out.close();
return stringWriter.toString();
}
}