Bob Swart (aka Dr.Bob)
Delphi 5 en CORBA Exceptions

Sinds eind 1999 is VisiBroker 3.3 voor Delphi 5 Enterprise gratis te downloaden van de Inprise website. Vorige keer zagen we een introduktie in het gebruik van de IDL-2-PAS, en deze keer wil ik het hebben over de ondersteuning voor CORBA Exceptions.

We kennen natuurlijk allemaal de standaard try-except en try-finally exceptions in Delphi. Maar Delphi is niet de enige taal die exceptions kent: ook Java en C++ kennen exceptions, alhoewel die daar met throw-catch om je oren vliegen. In CORBA's IDL (interface definition language) spreekt men weer van het "raisen" van exceptions, dus wat dat betreft lijkt het wat meer op de ObjectPascal variant die wij als Delphi gebruikers al kennen. Het IDL exception type is in feite een struct (een record in Delphi) dat verschillende data members kan bevatten, maar geen methoden (in tegenstelling tot Delphi exceptions, waaraan je wel methoden kunt toevoegen). In IDL hebben exceptions dus wel een toestand (de data members) maar geen gedrag. Dat is op zich ook niet zo onlogisch, want een CORBA exception wordt meestal door de CORBA server gegenereerd (met raise) en dan als foutboodschap naar de CORBA client gestuurd. Het heeft weinig zin om specifiek gedrag (methodes) toe te voegen aan de exception, als dit gedrag toch vaak geen betekenis heeft voor de client. En ik vermoed dat het toevoegen van callback methods aan exceptions gewoon een beetje teveel van het goede werd - zeker als je bedenkt dat IDL als onderdeel van CORBA door het OMG committee gestandardiseerd is.

Als we even terugdenken aan het IDL voorbeeld dat we de afgelopen nummers steeds als rode draad hebben gebruikt, dan hadden we in module DrBob42 een interface ISDGN met als methode TheAnswer. Deze method has als out argument een Answer van type long. Het kan echter voorkomen dat het antwoord nog niet bekend is (als men nog aan het rekenen is), of dat er iets anders misgaat. Dus laten we een exception NoAnswerYet definiëren dat aan zou moeten geven dat er nog geen antwoord bekend is (en dat men ook niet net als meneer van Dalen zou willen wachten op dat antwoord, want dat kan wel eens erg lang gaan duren). De IDL definitie van een exception NoAnswerYet is als volgt:

  exception NoAnswerYet
  {
  };
Merk op dat het woord exception hier (syntactisch gezien) als een soort reserved word wordt gebruikt: een soort struct definitie inderdaad. Om ook nog een data member "Reason" toe te voegen moeten we de IDL definitie als volgt aanpassen:
  exception NoAnswerYet
  {
    string Reason;
  };
De CORBA Server kan de Reason een waarde geven, en de exception NoAnswerYet raisen als het antwoord nog niet bekend is. Hoe dat (dan de server kant) gaat zal ik zo laten zien. Eerst zullen we de IDL moeten aanpassen met de exception definitie zelf. Bovendien moet in CORBA IDL - net als in andere talen maar helaas niet in Delphi - bij een method worden aangegeven welke exceptions er geraised kunnen worden in deze methode. Voor onze "TheAnswer" methode is dat de exception "NoAnswerYet", en dat ziet er alles bij elkaar als volgt uit:
  module DrBob42
  {
    exception NoAnswerYet
    {
      string Reason;
    };

    interface ISDGN
    {
      void TheAnswer(out long Answer) raises (NoAnswerYet);
    };

    interface SDGNFactory
    {
      ISDGN CreateInstance(in string InstanceName);
    }
  };
Overigens had de exception definitie ook binnen het interface ISDGN gedefinieerd kunnen worden. In dat geval kan niemand anders deze exception raisen, en dat wordt dan ook vaak gebruikt voor exceptions die slechts lokale betekenis hebben (iets wat hier eigenlijk ook geldt).

Standaard Exceptions
Er bestaan ook al een verzameling voorgedefinieerde exceptions in IDL, die we ook in Delphi's ObjectPascal terugvinden (mits de VisiBroker for Delphi 5 is geïnstalleerd). Ze zijn afgeleid van type SystemException, en staan in CORBA.PAS. Een lijstje van exception type name met betekenis is als volgt:

  type
    SystemException = class(Exception)

    UNKNOWN            De "unknown" exception
    BAD_PARAM          Een "invalid" parameter is doorgegeven
    NO_MEMORY          Geheugenallocatie faalde
    IMP_LIMIT          Overschreden implementatie limiet
    COMM_FAILURE       Communicatie fout
    INV_OBJREF         Invalide object referentie
    NO_PERMISSION      Geen permissie voor deze methode
    INTERNAL           Interne ORB fout
    MARSHAL            Marshal fout bij parameter of resultaat
    INITIALIZE         ORB initialisatie fout
    NO_IMPLEMENT       Implementatie van methode niet beschikbaar
    BAD_TYPECODE       Foute TypeCode
    BAD_OPERATION      Foute operatie (methode)
    NO_RESOURCES       Onvoldoende resource beschikbaar voor request
    NO_RESPONSE        Geen antwoord
    PERSIST_STORE      Persistente opslag mislukt
    BAD_INV_ORDER      Verkeerde aanroepvolgorde routines
    TRANSIENT          Transient failure
    FREE_MEM           Kan geheugen niet vrijgeven
    INV_IDENT          Foute identifier syntax
    INV_FLAG           Foute vlag meegegeven
    INTF_REPOS         Fout bij benadering Interface Repository
    BAD_CONTEXT        Fout bij afhandeling Context Object
    OBJ_ADAPTER        Fout gevonden bij Object Adaptor
    DATA_CONVERSION    Data conversie fout
    OBJECT_NOT_EXIST   Objet bestaat niet (meer) - verwijderen
Tot slot kennen we ook nog de UserException, een eigen type binnen CORBA, waar onze "NoAnswerYet" exception van afgeleid zal worden:
    UserException = class(Exception)

Exceptions Raisen
Omdat we zelfs met VisiBroker for Delphi geen CORBA servers op basis van IDL kunnen maken, zijn we gedwongen om de nieuwe CORBA server in bijvoorbeeld C++Builder of Java te maken. Ik heb hier voor C++Builder 4 Enterprise gekozen, en heb via IDL-2-CPP een Server Skeleton laten genereren voor C++Builder. De method ISDGNImpl::TheAnswer heb ik als volgt geïmplementeerd in C++Builder:

  void ISDGNImpl::TheAnswer(CORBA::Long Answer)
  {
    throw DrBob42::NoAnswerYet("De Server is nog niet klaar met rekenen...");
  //return 42;
  }
Dit natuurlijk alleen maar om de demonstreren dat we een exception aan de CORBA server kant kunnen genereren, die we vervolgens aan de CORBA client kant in Delphi kunnen opvangen en afhandelen.

Exception Afhandelen
Met de IDL2PAS kunnen we de nieuwe interface definities in DrBob42.IDL vertalen naar een nieuwe DrBob42_C.pas en DrBob42_I.pas. De DrBob42_C.pas bevat de Client Stub, waaronder de definitie (en implementatie) van de NoAnwerYet exception. Dit is te zien in onderstaand fragment:

  ENoAnswerYet = class(UserException)
  private
    FReason: AnsiString;
  protected
    function  _get_Reason: AnsiString; virtual;
  public
    property  Reason: AnsiString read _get_Reason;
    procedure Copy(const _Input : InputStream); override;
  end;
Wat opvalt is dat de exception NoAnswerYet een E voor de naam heeft gekregen in Delphi (terwijl we in C++Builder toch echt een exception van type NoAnswerYet konden raisen). Verder zien we de property Reason, en de rest is eigenlijk voor ons gebruik niet van belang. De code om de exception af te vangen is zoals we dat gewend zijn in Delphi met een normaal try-except blok:
  try
    Server.TheAnswer(Answer);
  except
    on E: ENoAnswerYet do
       ShowMessage(E.Reason);
  end;

Conclusie
VisiBroker for Delphi 5 biedt ondersteuning voor CORBA exceptions. Helaas nog niet voor CORBA servers geschreven in Delphi - deze maken nog gebruik van de Type Library die geen CORBA exceptions ondersteunt - maar wel voor CORBA clients geschreven in Delphi die communiceren met CORBA servers geschreven in een willkeurige andere taal die CORBA exceptions ondersteunt (zoals Java of C++Builder). Het wachten is nu op Kylix - de Delphi/C++Builder voor Linux die naar verwachting wel een volledig functionele VisiBroker implementatie zal bevatten, waaronder die voor Server Skeletons met ondersteuning voor exceptions. Ik verwacht dat die VisiBroker for Delphi dan ook nog voor Delphi 5 Enterprise beschikbaar komt, of anders uiterlijk in Delphi 6 Enterprise aanwezig zal zijn. Tegen die tijd zullen we nogmaals het ontwerp CORBA aansnijden, dat spreekt haast vanzelf...
Mocht iemand nog vragen, opmerkingen of suggesties hebben, dan hoor ik die het liefst via .


Dit artikel is eerder verschenen in SDGN Magazine #59 - 2000

This webpage © 1999-2006 by webmaster drs. Robert E. Swart (aka - www.drbob42.com). All Rights Reserved.