/*
 * 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.UnexpectedAlluxioException;
import alluxio.thrift.AlluxioTException;
import alluxio.thrift.ThriftIOException;

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 Alluxio or runtime exception
   */
  public static <T> T call(Logger logger, RpcCallable<T> callable) throws AlluxioTException {
    try {
      if (logger.isDebugEnabled()) { // Avoid expensive debug calls in critical path if disabled
        logger.debug("Enter: {}", callable.getCallInfo());
        T ret = callable.call();
        logger.debug("Exit: {}", callable.getCallInfo());
        return ret;
      } else {
        return callable.call();
      }
    } catch (AlluxioException e) {
      logger.debug("Internal Error: {}", callable.getCallInfo(), e);
      throw e.toThrift();
    } catch (Exception e) {
      logger.error("Unexpected Error: {}", callable.getCallInfo(), e);
      throw new UnexpectedAlluxioException(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 Alluxio or runtime exception
   * @throws ThriftIOException if the callable throws an IOException
   */
  public static <T> T call(Logger logger, RpcCallableThrowsIOException<T> callable)
      throws AlluxioTException, ThriftIOException {
    try {
      if (logger.isDebugEnabled()) { // Avoid expensive debug calls in critical path if disabled
        logger.debug("Enter: {}", callable.getCallInfo());
        T ret = callable.call();
        logger.debug("Exit: {}", callable.getCallInfo());
        return ret;
      } else {
        return callable.call();
      }
    } catch (AlluxioException e) {
      logger.debug("Internal Error: {}", callable.getCallInfo(), e);
      throw e.toThrift();
    } catch (IOException e) {
      logger.debug("I/O Error: {}", callable.getCallInfo(), e);
      throw new ThriftIOException(e.getMessage());
    } catch (Exception e) {
      logger.error("Unexpected Error: {}", callable.getCallInfo(), e);
      throw new UnexpectedAlluxioException(e).toThrift();
    }
  }

  /**
   * 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
     * @throws AlluxioException if an expected exception occurs in the Alluxio system
     */
    T call() throws AlluxioException;

    /**
     * @return printable call information in the format: "[Call Name]. arg1:value1, arg2:value2 ..."
     */
    String getCallInfo();
  }

  /**
   * 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
     * @throws AlluxioException if an expected exception occurs in the Alluxio system
     * @throws IOException if an exception is thrown when interacting with the underlying system
     */
    T call() throws AlluxioException, IOException;

    /**
     * @return printable call information in the format: "[Call Name]. arg1:value1, arg2:value2 ..."
     */
    String getCallInfo();
  }

  private RpcUtils() {} // prevent instantiation
}

@@ -1319,107 +1319,8 @@
 y %7B%0A
-      if (logger.isDebugEnabled()) %7B // Avoid expensive debug calls in critical path if disabled%0A  
     
@@ -1355,35 +1355,19 @@
 callable
-.getCallInfo()
 );%0A
-  
       T 
@@ -1387,34 +1387,32 @@
 e.call();%0A      
-  
 logger.debug(%22Ex
@@ -1428,35 +1428,19 @@
 callable
-.getCallInfo()
 );%0A
-  
       re
@@ -1453,63 +1453,8 @@
 et;%0A
-      %7D else %7B%0A        return callable.call();%0A      %7D%0A
     
@@ -1529,38 +1529,24 @@
 %7D%22, callable
-.getCallInfo()
 , e);%0A      
@@ -1640,38 +1640,24 @@
 %7D%22, callable
-.getCallInfo()
 , e);%0A      
@@ -2331,107 +2331,8 @@
 y %7B%0A
-      if (logger.isDebugEnabled()) %7B // Avoid expensive debug calls in critical path if disabled%0A  
     
@@ -2367,35 +2367,19 @@
 callable
-.getCallInfo()
 );%0A
-  
       T 
@@ -2403,26 +2403,24 @@
 ll();%0A      
-  
 logger.debug
@@ -2444,27 +2444,11 @@
 able
-.getCallInfo()
 );%0A
-  
     
@@ -2465,63 +2465,8 @@
 et;%0A
-      %7D else %7B%0A        return callable.call();%0A      %7D%0A
     
@@ -2541,38 +2541,24 @@
 %7D%22, callable
-.getCallInfo()
 , e);%0A      
@@ -2647,38 +2647,24 @@
 %7D%22, callable
-.getCallInfo()
 , e);%0A      
@@ -2791,22 +2791,8 @@
 able
-.getCallInfo()
 , e)
@@ -3272,152 +3272,8 @@
 ion;
-%0A%0A    /**%0A     * @return printable call information in the format: %22%5BCall Name%5D. arg1:value1, arg2:value2 ...%22%0A     */%0A    String getCallInfo();
 %0A  %7D
@@ -3817,152 +3817,8 @@
 ion;
-%0A%0A    /**%0A     * @return printable call information in the format: %22%5BCall Name%5D. arg1:value1, arg2:value2 ...%22%0A     */%0A    String getCallInfo();
 %0A  %7D

Simplify interface.