Плохая идея связать исключения с RMI? - PullRequest
2 голосов
/ 09 декабря 2008

Это плохая идея использовать цепочку исключений при создании исключений RemoteExceptions? У нас есть RMI-сервер, который делает что-то вроде этого:

public Object doSomething() throws RemoteException
{
    try
    {
        return getData();
    }
    catch (CustomException ex)
    {
        throw new RemoteException(ex);
    }
}

Я получаю UnmarshallException, вызванное ClassNotFoundException в моем клиенте. С другой стороны, получается, что сама CustomException экспортируется. К сожалению, еще одно исключение глубоко внутри этого парня НЕ экспортируется, и здесь возникает исключение ClassNotFoundException. Я думаю, что иерархия выглядит примерно так:

RemoteException -> CustomException -> SQLException -> NotExportedException

Проблема, которую я вижу, состоит в том, что, хотя мы можем гарантировать, что CustomException экспортируется, мы не можем гарантировать, что существуют исключения более низкого уровня.

Я склоняюсь к НИКОГДА, используя цепочку исключений с RemoteExceptions из-за этого. Вместо этого я думаю, что мне, вероятно, следует зарегистрировать трассировку стека на стороне сервера и выдать простое ванильное RemoteException без привязки к «причине». Кто-нибудь имел дело с этой ситуацией раньше?

Ответы [ 2 ]

5 голосов
/ 09 декабря 2008

Вместо того, чтобы помещать CustomException в RemoteException, вы можете изменить свой удаленный интерфейс следующим образом:

interface Foo extends Remote {

  Object doSomething() throws CustomException, RemoteException;

}

Принцип здесь заключается в том, что только время выполнения RMI должно вызывать исключения RemoteException; они сигнализируют о некотором сбое в удаленном взаимодействии, а не в логике приложения. Фактически, конкретным реализациям даже не нужно объявлять RemoteException.

Но это не относится к случаю, когда ваш сервис перехватывает исключение из какой-либо сторонней библиотеки, но не хочет раскрывать это в предложении throws.

public Object doSomething() throws CustomException {
  try {
    return theirSvc.getData();
  } catch (ThirdPartyException ex) {
    throw new CustomException("Failed to obtain requested data.");
    // or: throw new CustomException("Failed to obtain requested data.", ex) ?
  }
}

В этом случае я рекомендую вам не создавать «негерметичную абстракцию», когда в клиенте будет создана зависимость, которая иначе не должна была бы знать об этой сторонней библиотеке.

Обычно ведение журнала и является плохой практикой, поскольку одна и та же ошибка регистрируется повторно. Но в этом случае я думаю, что это оправдано, поскольку выброшенное исключение переносится на клиента; может быть полезно зарегистрировать его как на клиенте, так и на сервере. Таким образом, блок catch выглядит примерно так:

catch (ThirdPartyException ex) {
   String message = "Failed to obtain requested data.";
   log.error(message, ex);
   throw new CustomException(message);
 }

Таким образом, зависимость ThirdPartyException ограничивается сервером, журналы сервера содержат соответствующую информацию о реализации, а ошибка правильно передается клиенту.

3 голосов
/ 09 декабря 2008

Мы фиксируем сообщение + трассировку всего стека из исходного исключения и передаем его как содержимое удаленного исключения. Таким образом, вы получаете все детали стека, но вам не нужно беспокоиться о том, что ЛЮБОЕ из внутренних исключений не будет сериализуемым.

Вы никогда не знаете, какие другие объекты могут находиться внутри какой-либо другой третьей стороны (или даже ваших собственных пользовательских исключений!)

...