Try OpenEdge Now
skip to main content
Object-oriented Programming
Programming with Class-based Objects : Raising and handling error conditions : Raising errors within a method : Method error handling example
 
Method error handling example
The following class fragments from the sample classes show an example of method error handling:
ROUTINE-LEVEL ON ERROR UNDO, THROW.
USING acme.myObjs.Common.*.

CLASS acme.myObjs.CreditObj:
  ...
  METHOD PUBLIC VOID SetCurrentCustomer (INPUT piCustNum AS INTEGER):
    /* Verify that this object has the current    */
    /* Customer before the property is referenced */
    FIND FIRST Customer WHERE Customer.CustNum = piCustNum NO-ERROR.
  END METHOD.

  METHOD PUBLIC VOID CheckCustCredit ( ):
    /* invokes the CustCreditLimit property SET accessor */
    IF AVAILABLE (Customer) THEN
      CustCreditLimit = Customer.Creditlimit.
    ELSE
      UNDO, THROW NEW Progress.Lang.AppError("No Customer").
  END METHOD.
END CLASS.
The CheckCustCredit( ) method of acme.myObjs.CreditObj throws an error object for two different conditions, which are distinguished by the error return string returned in the ReturnValue property of the Progress.Lang.AppError object. Note that the object returning the "No Customer" string is created using the NEW function, and another error object containing the "Over Limit" can be thrown from an error condition raised in the SET accessor of the CustCreditLimit property (see the code for this property in the ). The ROUTINE-LEVEL ON ERROR UNDO, THROW statement that begins the class definition ensures that any error objects not caught and consumed by methods of the class are thrown to a method’s caller.
Also note that to make a Customer record available, the SetCurrentCustomer( ) method must be successfully invoked prior to invoking CheckCustCredit( ). SetCurrentCustomer( ) relies on the NO-ERROR option of a FIND statement to complete with an error raised because no record is found with the specified criteria. So, instead of using structured error handling for this situation in both methods, CheckCustCredit( ) checks for record availability to handle that particular error.
The CheckCredit( ) method of acme.myObjs.CustObj then invokes these methods in the correct sequence and, if ERROR is raised, checks the value of the ReturnValue property on the error object to handle the error condition appropriately, as shown:
USING acme.myObjs.*.
USING acme.myObjs.Common.*.
USING acme.myObjs.Interfaces.*.

CLASS acme.myObjs.CustObj INHERITS CommonObj
                          IMPLEMENTS IBusObj:

  DEFINE PUBLIC VARIABLE iNumCusts AS INTEGER NO-UNDO.
  DEFINE PROTECTED TEMP-TABLE ttCustomer NO-UNDO
    FIELD RecNum  AS INTEGER
    FIELD CustNum LIKE Customer.CustNum
    FIELD Name    LIKE Customer.Name
    FIELD State   AS CHARACTER.
  DEFINE PRIVATE VARIABLE rCreditObj AS CLASS CreditObj NO-UNDO.
  DEFINE PRIVATE VARIABLE rMsg       AS CLASS MsgObj    NO-UNDO.

  ...

  METHOD PUBLIC VOID CheckCredit ( ):
    IF VALID-OBJECT (rCreditObj) THEN DO:
      FOR EACH ttCustomer:
        rCreditObj:SetCurrentCustomer (ttCustomer.CustNum).
        rCreditObj:CheckCustCredit ( ).

        /* invokes the CustCreditLimit property GET accessor */
        rMsg:InfoMsg(ttCustomer.Name + " is in good standing." +
          "  Credit Limit has been increased to " +
          STRING(rCreditObj:CustCreditLimit)).

        CATCH e AS Progress.Lang.AppError:
          IF e:ReturnValue = "Over Limit" THEN DO:
            /* invokes the CustCreditLimit property GET accessor */
            rMsg:Alert(ttCustomer.Name + " is on Credit Hold." +
              "  Balance exceeds Credit Limit of " +
              STRING (rCreditObj:CustCreditLimit)).
          END.
          ELSE
            rMsg:Alert ("Customer not found").
        END CATCH.
      END. /* FOR EACH */
    END.
    ELSE rMsg:Alert ("Unable to check credit").
  END METHOD.

  ...

END CLASS.