Межмодульная передача ошибок в iJaNet Framework

Автор: Антон Сержантов
Компания: Janet systems

В JaNet Framework два модуля могут взаимодействовать друг с другом посредством вызова методов сервисов. Один модуль обращается к сервису другого модуля через прокси (подробнее см. здесь). Если в вызываемом методе сервиса возникла ошибка, то она передастся в точку вызова в вызывающий модуль в "чистом виде", если тип ошибки может быть приведен к одному из типов перечисленных в сигнатуре throws вызываемого метода. Иначе ошибка будет "упакована" проксей на клиентской стороне в UndeclaredThrowableException (подробнее см. здесь).
Рассмотрим вышесказанное подробнее не примере.

Пример межмодульной передачи ошибки в iJaNet Framework

Пусть в системе есть два модуля А и В. Пусть в модуле А вызывается сервис модуля В.

Метод сервиса:

1 public void Execute(){
2    try{
3      ...
4    }
5    catch(Throwable th){
6       throw new MyException("My service execution failed", th);
7    }
8 }

Объявление класса ошибки

1 ...
2 public class MyException extends Throwable{
3 ...
4 }

Вызов сервиса MyService в модуле А

 1 ...
 2 try{
 3   MyService mySvc = (MyService)Services.getService("my_service");
 4   mySvc.Execute();
 5 }
 6 catch(Throwable th)  {
 7 ...
 8 }
 9 ...

При таком объявлении метода Execute() в модуле А в блоке catch придет ошибка с типом UndeclaredThrowableException с вложенной ошибкой типа MyException, т.к. передается ошибка с типом MyException, а в сигнатуре метода не указано ни одного типа ошибок (нет выражения throws). Для того, чтобы в блок catch в модуле А пришла ошибка типа MyException, необходимо добавить в объявление метода Execute() вот такое выражение

1 public void Execute() throws MyException /*или throws Throwable*/{
2    try{
3      ...
4    }
5    catch(Throwable th){
6       throw new MyException("My service execution failed", th);
7    }
8 }

Теперь после объявления типа передаваемых ошибок, прокси в модуле А сможет привести пришедший тип ошибки к типу MyExcepiton (или Throwable).

Рекомендации по выбору типа ошибок, декларируемых в сигнатурах методов сервиса

В этой главе будет дана рекомендация по построению иерархии классов ошибок в системе iJaNet Framework. Правило всего одно и достаточно простое:
Все классы новых ошибок рекомендуется наследовать от типа jws.core.services.ServiceException и объявлении его в сигнатуре метода сервиса в выражении throws
Данная рекомендация связана с тем, что до момента вызова непосредственно метода сервиса могут возникнуть ошибки внутри платформы, связанные с инициализацией сервиса, создания экземпляра сервиса и т.д. Все эти ошибки упаковываются в jws.core.services.ServiceException и передаются в вызывающий модуль. Таким образом, если в сигнатуре метода сервиса не будет указан данный тип, то подобные ошибки будут оборачиваться в UndeclaredThrowableException проксей на вызывающей стороне.
В итоге, рекомендуемая иерархия классов ошибок должна выглядеть следующим образом

Рекомендуемая сигнатура методов сервиса

1 ...
2 public interface IMyService {
3    ...
4    public void method1() throws ServiceException;
5    public void method2() throws ServiceException;
6    ...    
7 }

И соответственно обработка ошибок на вызывающей стороне может выглядеть так

 1 ...
 2 try{
 3    IMyService mySvc;
 4    ... 
 5    mySvc.method1();
 6    ...
 7    mySvc.method2();
 8    ...  
 9 }
10 catch(MyCustomException ex1)   {
11    ...
12 }
13 catch(MyCustomException1 ex2)   {
14    ...
15 }
16 catch(ServiceException ex3)   {
17    //Системная ошибка в инициализации сервиса
18 }
19 ...

Пример передачи ошибок в Remoting

Если речь идет о Remoting, то алгоритм передачи ошибок тот же, что и для сервисов с некоторой поправкой. Пусть, для примера, в системе также есть два модуля А и В, модуль А вызывает метод удаленного объекта модуля В

Метод Perform() удаленного объекта

1 public void Perform() throws MyRemoteObjectException
2    try{
3    ...
4    }
5    catch(Throwable th)   {
6       throw new MyRemoteObjectException("Method Perform() invocation failed", th);
7    }
8 }

Класс ошибки

1 public class MyRemoteObjectException extends Throwable{
2    ...
3 }

При таких обстоятельствах на стороне, вызывающей метод Perform() удаленного объекта MyRemoteObject, ошибка MyRemoteObjectException в чистом виде не придет никогда. И вот такой блок catch

 1 ...
 2 try{
 3    ...  //вызов метода удаленного объекта
 4 }
 5 catch(MyRemoteObjectException ex){
 6    ...
 7 }
 8 ...
 9 }

никогда не сработает. Дело в том, что вызов метода удаленного объекта происходит через IRemotingService сервис, в частности через метод IRemotingService.invokeObject(...). Внутри этого метода все возникшие ошибки методов удаленных объектов "упаковываются" в RemotingException и передаются вызывающей стороне. Поэтому корректный код на стороне модуля А, вызывающий метод удаленного объекта, будет выглядеть так

 1 ...
 2 IRemoteObject myRO;
 3 try{
 4    myRO = Remoting.createObject("MyRemoteObject", "remoting");  //создание экземпляра класса MyRemoteObject на стороне модуля В через
 5                                                                 //IRemotingService сервис с локальным именем 'remoting'
 6 }
 7 catch(RemotingException ex){
 8    ... //ошибка создания прокси для удаленного объекта
 9 }
10 try{
11     myRO.invoke("Perform", new TypedValue[0]);  //Вызов метода
12 }
13 catch(RemotingException re){
14    MyRemoteObjectException myEx = (MyRemoteObjectException )re.getCause();
15    throw myEx;
16 }
17 ...

Exceptions_Advise1.jpg (30 KB) Виталий Шакуров, 04/30/2010 01:10 am

Exceptions_Remoting.jpg (25.7 KB) Виталий Шакуров, 04/30/2010 01:10 am

Exceptions_Example1.jpg (18.7 KB) Виталий Шакуров, 04/30/2010 01:10 am

Also available in: HTML TXT