/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio;
import alluxio.exception.AlluxioException;
import alluxio.exception.status.AlluxioStatusException;
import alluxio.exception.status.InternalException;
import alluxio.thrift.AlluxioTException;
import org.slf4j.Logger;
import java.io.IOException;
/**
* Utilities for handling RPC calls.
*/
public final class RpcUtils {
/**
* Calls the given {@link RpcCallable} and handles any exceptions thrown.
*
* @param logger the logger to use for this call
* @param callable the callable to call
* @param <T> the return type of the callable
* @return the return value from calling the callable
* @throws AlluxioTException if the callable throws an exception
*/
public static <T> T call(Logger logger, RpcCallable<T> callable) throws AlluxioTException {
try {
return callable.call();
} catch (AlluxioException e) {
logger.debug("{}, Error={}", callable, e.getMessage());
throw AlluxioStatusException.fromAlluxioException(e).toThrift();
} catch (RuntimeException e) {
logger.error("{}", callable, e);
throw new InternalException(e).toThrift();
}
}
/**
* Calls the given {@link RpcCallableThrowsIOException} and handles any exceptions thrown.
*
* @param logger the logger to use for this call
* @param callable the callable to call
* @param <T> the return type of the callable
* @return the return value from calling the callable
* @throws AlluxioTException if the callable throws an exception
*/
public static <T> T call(Logger logger, RpcCallableThrowsIOException<T> callable)
throws AlluxioTException {
try {
return callable.call();
} catch (AlluxioException e) {
logger.debug("{}, Error={}", callable, e.getMessage());
throw AlluxioStatusException.fromAlluxioException(e).toThrift();
} catch (IOException e) {
logger.warn("{}, Error={}", callable, e.getMessage());
logger.debug("{}", callable, e);
throw AlluxioStatusException.fromIOException(e).toThrift();
} catch (RuntimeException e) {
logger.error("{}", callable, e);
throw new InternalException(e).toThrift();
}
}
/**
* Calls the given {@link RpcCallable} and handles any exceptions thrown. The callable should
* implement a toString with the following format: "CallName: arg1=value1, arg2=value2,...".
* The toString will be used to log enter and exit information with debug logging is enabled.
*
* @param logger the logger to use for this call
* @param callable the callable to call
* @param <T> the return type of the callable
* @return the return value from calling the callable
* @throws AlluxioTException if the callable throws an Alluxio or runtime exception
*/
public static <T> T callAndLog(Logger logger, RpcCallable<T> callable) throws AlluxioTException {
logger.debug("Enter: {}", callable);
try {
T ret = call(logger, callable);
logger.debug("Exit (OK): {}", callable);
return ret;
} catch (AlluxioTException e) {
logger.debug("Exit (Error): {}, Error={}", callable, e.getMessage());
throw e;
}
}
/**
* Calls the given {@link RpcCallableThrowsIOException} and handles any exceptions thrown. The
* callable should implement a toString with the following format:
* "CallName: arg1=value1, arg2=value2,...". The toString will be used to log enter and exit
* information with debug logging is enabled.
*
* @param logger the logger to use for this call
* @param callable the callable to call
* @param <T> the return type of the callable
* @return the return value from calling the callable
* @throws AlluxioTException if the callable throws an Alluxio or runtime exception
*/
public static <T> T callAndLog(Logger logger, RpcCallableThrowsIOException<T> callable)
throws AlluxioTException {
logger.debug("Enter: {}", callable);
try {
T ret = call(logger, callable);
logger.debug("Exit (OK): {}", callable);
return ret;
} catch (AlluxioTException e) {
logger.debug("Exit (Error): {}, Error={}", callable, e.getMessage());
throw e;
}
}
/**
* An interface representing a callable which can only throw Alluxio exceptions.
*
* @param <T> the return type of the callable
*/
public interface RpcCallable<T> {
/**
* The RPC implementation.
*
* @return the return value from the RPC
*/
T call() throws AlluxioException;
}
/**
* An interface representing a callable which can only throw Alluxio or IO exceptions.
*
* @param <T> the return type of the callable
*/
public interface RpcCallableThrowsIOException<T> {
/**
* The RPC implementation.
*
* @return the return value from the RPC
*/
T call() throws AlluxioException, IOException;
}
/**
* An interface representing a netty RPC callable.
*
* @param <T> the return type of the callable
*/
public interface NettyRPCCallable<T> {
/**
* The RPC implementation.
*
* @return the return value from the RPC
*/
T call() throws Exception;
/**
* Handles exception.
*
* @param throwable the exception
*/
void exceptionCaught(Throwable throwable);
}
/**
* Handles a netty RPC callable with logging.
*
* @param logger the logger
* @param callable the netty RPC callable
* @param <T> the return type
* @return the rpc result
*/
public static <T> T nettyRPCAndLog(Logger logger, NettyRPCCallable<T> callable) {
logger.debug("Enter: {}", callable);
try {
T result = callable.call();
logger.debug("Exit (OK): {}", callable);
return result;
} catch (Exception e) {
logger.debug("Exit (Error): {}, Error={}", callable, e.getMessage());
callable.exceptionCaught(e);
}
return null;
}
private RpcUtils() {} // prevent instantiation
}