Defining the callbacks attached to each button is straightforward. Recall that in CAPI, because we stated that the button callback type was:interface, the argument passed to a callback is the interface whose activation triggered that callback.
Thecredit-callback is activated by the Credit button of someaccount interface:
(defun credit (self)
(with-slots (balance-field account-ref) self
(let ((amount (capi:prompt-for-integer "Amount?" :min 0)))
(when amount
(op:credit account-ref amount)
(setf (capi:display-pane-text balance-field)
(format nil "~A" (op:balance account-ref)))))))
The callback is passed theaccount interface. It then extracts the CORBA object reference stored in the frame'saccount-ref slot and prompts the user for an amount. The functioncapi:prompt-for-integer queries the user for an integer and returns nil if the user cancels the dialog. If the amount is valid, the callback invokes the stub methodop:credit on the CORBA object reference with the specified absolute value of the amount (recall that thecredit operation expects an unsignedlong as its argument). Finally, it updates thebalance field of the frame with the current value of the object'sbalance attribute, obtained by invoking the stub methodop:balance.
The definition ofdebit-callback is very similar to the definition ofcredit-callback:
(defun debit (self)
(with-slots (balance-field account-ref) self
(let ((amount (capi:prompt-for-integer "Amount?" :min 0)))
(when amount
(handler-case
(progn
(op:debit account-ref amount)
(setf (capi:display-pane-text balance-field)
(format nil "~A" (op:balance account-ref))))
(BankingDemo:account/refusal
(xx)
(capi:display-message "Debit returned refusal with
string: <~A>"
(op:reason xx))))))))
The only difference is thatdebit-callback must deal with the additional possibility that thedebit operation, when invoked on the target object, may fail, raising the IDL exception refusal. If the object raises this exception, theop:debit stub method signals it as a Common Lisp condition of classBankingDemo:account/refusal.
The exception can then be caught and handled in any of the standard Common Lisp ways. Here, we simply place the invocation in the body of ahandler-case statement with an appropriate exception clause to handle the condition.
Theopen-account-callback is activated by theopenAccount-button of some bank frame:
(defun open-account-callback (self)
(with-slots (bank-ref) self
(let ((name (capi:prompt-for-string "Name?")))
(when name
(handler-case
(let ((account-ref
(op:openaccount bank-ref name)))
(make-account-frame account-ref
:bank-interface self :title name))
(Bankingdemo:Bank/DuplicateAccount
()
(capi:display-message "Cannot create account for
~A" name)))))))
The callback extracts the CORBA object reference stored in the interface'sbank-ref slot. The functioncapi:prompt-for-stringqueries the user for the new customer's name returning a string (or nil if the user cancels the dialog). If the dialog has not been cancelled, the callback invokes the stub methodop:openAccount on the target object reference bank, passing the argument name. If successful, the invocation returns an object reference, of classBankingDemo:account, to an IDL account object, which is then used to make and start a newaccount-interface, via a call tomake-account-frame.
Recall that the IDL operationopenAccount may fail, raising the IDL user exceptionduplicateAccount. As in the definition ofdebit-callback, we cater for this eventuality by placing the invocation in the body of ahandler-case statement and install a handler on the corresponding Common Lisp condition of classBankingDemo:bank/duplicateAccount. This handler simply informs the user of the exception using the CAPI functiondisplay-message to create and display a simple alert dialog box.
The definition ofopen-checking-account-callback is similar to the definition ofopenAccount-callback but prompts the user for an additional integer to pass as the overdraft limit of the new checking account:
(defun open-checking-account-callback (self)
(with-slots (bank-ref) self
(let ((name (capi:prompt-for-string "Name?")))
(when name
(let ((limit (capi:prompt-for-integer "Limit?")))
(when limit
(handler-case
(let ((account-ref
(op:opencheckingaccount bank-ref
name limit)))
(make-account-frame account-ref
:bank-interface self :title name))
(Bankingdemo:Bank/DuplicateAccount
()
(capi:display-message "Cannot create another
account for ~A" name)))))))))
WhileopenAccount andopenCheckingAccount create accounts for new customers, theretrieveAccount operation is simply meant to look up the account of an existing customer:
(defun retrieve-account-callback (self)
(with-slots (bank-ref) self
(let ((name (capi:prompt-for-string "Name?")))
(when name
(if (find-named-frame self name)
(capi:display-message "Already viewing it...")
(handler-case
(let ((account-ref
(op:retrieveaccount bank-ref name)))
(when (op:Is_a account-ref (op:id
Bankingdemo:_Tc_Checkingaccount))
(setf account-ref
(op:narrow 'Bankingdemo:Checkingaccount
account-ref)))
(make-account-frame account-ref
:bank-interface self :title name))
(Bankingdemo:Bank/NonExistentAccount
()
(capi:display-message "No account exists for
name ~A" name))))))))
This callback incorporates a test that prevents the user from being presented with more than one interface to the same account. It invokes the stub methodop:retrieveAccount only if the account under that name is not already on display. Because of IDL inheritance, the server implementing the IDLretrieveAccount operation may return any object reference whose interface inherits from the IDL account interface.
In particular, the server may return an IDLcheckingAccount as a special instance of an IDL account. In Common Lisp terms, this means that the stub methodOp:retrieveAccount may return an object reference of classBankingDemo:checkingAccount as a special instance ofBankingDemo:account. The call tomake-account-frame dispatches on the actual, or most derived, class of the resulting object reference, making anaccount-interface orchecking-account-interface as appropriate.
The definition of theclose-account-callback is straightforward:
(defun close-account-callback (self)
(with-slots (bank-ref) self
(let ((name (capi:prompt-with-list (all-frame-names self)
"Choose account")))
(when name
(op:closeaccount bank-ref
(with-slots (account-ref)
(find-named-frame self name)
account-ref))
(remove-account-frame self name)))))
The functionprompt-with-list presents a dialog asking the user to select a name from the list of available account frames (indexed by theiraccount-name), returning nil if the user decides to cancel the dialog. Given a valid selection, the callback invokes the stub methodop:closeAccount on the target object reference,bank-ref, passing the name of the selected account. Finally, the account interface is removed from the bank interface.