Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Advanced CORBA Programming wit C++ - M. Henning, S. Vinoski.pdf
Скачиваний:
64
Добавлен:
24.05.2014
Размер:
5 Mб
Скачать

IT-SC book: Advanced CORBA® Programming with C++

4.10 System Exceptions

CORBA makes remote communication as transparent as possible. At the source code level, sending a message to a CORBA object looks the same whether the object is implemented on a remote machine, is implemented in a different process on the same machine, or is actually linked into the client. However, by necessity, remote communication means that many more things can go wrong than for a local call. For example, connectivity may be lost because a bulldozer tears a cable.

IDL defines a number of system exceptions to capture common error conditions. Any operation can raise a system exception even if the operation has no raises expression.

IDL defines 29 system exceptions. System exceptions have different names, but they all use the same exception body. The following definition uses the preprocessor to define a notational shorthand for the body of all the system exceptions (we will discuss the meaning of the data members in a moment):

enum completion_status {

 

 

COMPLETED_YES, COMPLETED_NO, COMPLETED_MAYBE

 

};

 

\

#define SYSEX(NAME) exception NAME {

minor;

unsigned long

\

completion_status

completed;

\

}

 

 

The system exceptions themselves are defined as follows.

SYSEX(BAD_CONTEXT);

// error processing context object

SYSEX(BAD_INV_ORDER);

// routine invocations out of order

SYSEX(BAD_OPERATION);

// invalid operation

SYSEX(BAD_PARAM);

// an invalid parameter was passed

SYSEX(BAD_TYPECODE);

// bad typecode

SYSEX(COMM_FAILURE);

// communication failure

SYSEX(DATA_CONVERSION);

// data conversion error

SYSEX(FREE_MEM);

// cannot free memory

SYSEX(IMP_LIMIT);

// violated implementation limit

SYSEX(INITIALIZE);

// ORB initialization failure

SYSEX(INTERNAL);

// ORB internal error

SYSEX(INTF_REPOS);

// interface repository unavailable

SYSEX(INVALID_TRANSACTION);

// invalid TP context passed

SYSEX(INV_FLAG);

// invalid flag was specified

SYSEX(INV_IDENT);

// invalid identifier syntax

SYSEX(INV_OBJREF);

// invalid object reference

SYSEX(INV_POLICY);

// invalid policy override

SYSEX(MARSHAL);

// error marshaling param/result

SYSEX(NO_IMPLEMENT);

// implementation unavailable

SYSEX(NO_MEMORY);

// memory allocation failure

SYSEX(NO_PERMISSION);

// no permission for operation

SYSEX(NO_RESOURCES);

// out of resources for request

SYSEX(NO_RESPONSE);

// response not yet available

SYSEX(OBJECT_NOT_EXIST);

// no such object

SYSEX(OBJ_ADAPTER);

// object adapter failure

93

IT-SC book: Advanced CORBA® Programming with C++

SYSEX(PERSIST_STORE);

// persistent storage failure

SYSEX(TRANSACTION_REQUIRED);

// operation needs transaction

SYSEX(TRANSACTION_ROLLEDBACK);

// operation was a no-op

SYSEX(TRANSIENT);

// transient error, try again later

SYSEX(UNKNOWN);

// the unknown exception

Some of these exceptions, such as NO_MEMORY, have the obvious meaning. The meaning of others, such as BAD_INV_ORDER, is less obvious. Rather than list the meaning of every exception in detail here, we point out their uses as we discuss the relevant topic throughout the remainder of this book. The CORBA specification itself does not precisely state under exactly what circumstances each exception should be raised, so you have to expect different behavior from different ORBs (see Section 7.15.2).

An operation definition must not include system exceptions in its raises expression. It is understood that all operations may raise system exceptions. You are not allowed to explicitly state that, so the following is in error:

interface X {

// Illegal!

void op1() raises(BAD_PARAM);

void op2() raises(CORBA::BAD_PARAM);

// Illegal!

};

 

The list of system exceptions is open-ended and is occasionally added to by updates to the CORBA specification. To be future-proof, your code must be prepared to handle system exceptions not included in the preceding list in at least a general manner. If your code simply dumps core if it gets a new system exception, you will likely get problems as ORBs are upgraded over time (Section 7.15 shows how to deal with this problem).

A system exception body contains two data members: minor and completed. The completed member tells you at what point during call dispatch a failure occurred.

COMPLETED_YES

The failure occurred sometime after the operation in the server completed. This tells you that any state changes made by the failed invocation have happened.

Knowledge of whether the operation completed on the server side is important if an operation is not idempotent. An operation is idempotent if invoking it twice has the same effect as invoking it once. For example, the statement x=1; is idempotent, whereas the statement x++; is not.

COMPLETED_NO

The failure occurred on the way out of the client address space or on the way into the server address space. It is guaranteed that the target operation was not invoked, or, if it was invoked, no side effects of the operation have taken effect.

COMPLETED_MAYBE

94

IT-SC book: Advanced CORBA® Programming with C++

The completion status is indeterminate. This typically happens if the client invokes an operation and loses connectivity with the server while the call is still in progress. In this case, there is no way for the client run time to decide whether the operation was actually invoked in the server or whether the problem occurred before the request reached the servant.

The minor data member in system exceptions is meant to convey additional information about the exact cause of a failure with an error code. Unfortunately, CORBA does not specify the meaning of the minor codes and leaves their assignment to each ORB implementation (ORB vendors can reserve a section of minor code values for their exclusive use). For you as a developer, this means that there is no way to interpret the minor member in your program, at least not if you want to write portable code.

However, the minor code can be useful for debugging if an ORB vendor uses it to provide further information about the precise cause of a system exception. This means that you should at least show the minor code when you report or log a system exception (even though you cannot interpret the minor code programmatically).

4.11 System Exceptions or User Exceptions?

As you will see in Chapter 9, the implementation of an operation in the server can raise system exceptions as well as the user exceptions in the operation's raises expression. Consider again the EmployeeRegistry interface from Section 2.4.2:

interface EmployeeRegistry {

Employee lookup(in long emp_number);

};

The question is, how should lookup behave if it is called with a non-existent employee number? One option is to return a nil reference to indicate a failed lookup. This is certainly acceptable, in particular if you anticipate that clients will look for non-existent employees as part of normal operation.

However, you may decide that it would be better to treat lookup of a non-existent employee as an error condition and to raise an exception. Because lookup does not have a raises expression, you must pick a system exception to indicate that an employee number is unknown. Looking through the list of system exception on page 92, a likely choice is BAD_PARAM.

For an operation as simple as lookup, raising a BAD_PARAM exception may be OK. However, it is bad practice to rely on system exceptions to indicate application-level errors. For example, consider the following modified version of lookup:

interface EmployeeRegistry {

Employee lookup(in string emp_name, in string emp_birthday);

};

95

IT-SC book: Advanced CORBA® Programming with C++

With this version of the interface, we must supply both a name and a birth date to locate an employee. The problem now is that there are several possible error conditions. For example, the supplied name could denote a non-existent employee, or the birth date could be malformed (for example, the birth date could be the empty string). If lookup still raises BAD_PARAM to indicate failure to locate an employee, the client can no longer tell which parameter was considered in error. Moreover, the ORB run time itself may raise a BAD_PARAM exception, for example if a null pointer is passed to lookup (it is illegal to pass null pointers across IDL interfaces). In that case, the client has yet another problem because, on receipt of a BAD_PARAM exception, it can no longer tell whether the exception was raised by the ORB run time or by the application code in the server.

For these reasons, we recommend that you always define appropriate user exceptions for application-level error conditions. This approach not only ensures that error reporting takes place at the appropriate level of detail, but it also allows the client to distinguish application errors from platform errors (something that can be essential for debugging).

4.12 Oneway Operations

IDL permits an operation to be declared as oneway:

interface Events {

oneway void send(in EventData data);

};

Intuitively, oneway operations are intended for building unreliable signaling mechanisms with semantics similar to UDP datagrams (the send-and-forget approach).

A oneway operation must adhere to the following rules.

It must have return type void.

It must not have any out or inout parameters. It must not have a raises expression.

These restrictions exist to disallow any traffic in the return direction from server to client. Because user exceptions are return values in disguise, they are included in the preceding list of restrictions. However, oneway calls may raise system exceptions.

Oneway operations have "best effort" semantics. This means that oneway calls may not be delivered but are guaranteed to be delivered at most once. Beyond this, the CORBA specification says nothing about the semantics of oneway. For example, an ORB that simply drops every oneway call on the floor is a compliant implementation. (Its best effort happens to be a very poor one.) Conversely, an ORB is entitled to simply ignore the oneway keyword and to dispatch oneway calls in the same way as any other call. (That ORB's best effort is a particularly good one because oneway calls are as reliable as ordinary calls.)

96