Archived

This forum has been archived. Please start a new discussion on GitHub.

What is the best practice for using Ice::Context?

I am looking at using Ice::Context in my application to pass implicit parameters that are present in almost every function call (session key, database transaction identifier). This seems to be the best solution, and indeed appears to be recommended by the Ice::Context description in section 21.12.6 of the documentation.

However, I am having second thoughts because section 4.22.2 (comparing ICE with CORBA) dismisses CORBA contexts as a misfeature that destroys type safety and results in "systems that are hard to understand, code and debug". It seems like these criticisms could also be levelled at Ice contexts, to some extent (although maybe there's some difference between the two that I am not aware of).

So, are there any traps that I need to be aware of when using Ice::Context? Is there an alternative, better, approach for using this kind of parameter (authentication keys, transaction ID's, etc.) in ICE?

Comments

  • CORBA contexts and Ice contexts are similar, but not the same. With CORBA, you have to declare the context in the operation signature--only context parameters that are named in the signature are actually transmitted to the server. However, that makes CORBA contexts non-transparent because, if you want to change what context information is transmitted, you must recompile and redeploy all clients and servers. With Ice, context information is truly transparent: whatever context information is sent by the client is received by the server, with no change to the Slice definition.

    The comments about type safety stand: contexts are untyped strings and therefore a much less safe mechanism (and less efficient) than properly typed operation parameters. And, as we point out in the documentation, abusing contexts to implement versioning and add parameters to an operation in order to avoid changing the Slice definitions is a bad idea.

    Contexts are intended for infrastructure services that require additional information to be sent with every invocation. The canonical example is a distributed transaction service that requires a transaction ID with every RPC. Without contexts, it would be impossible to create transactional and non-transactional versions of an application without also splitting the type system into two halves. The original CORBA transaction service had this problem because it required interfaces to derive from a TransactionalObject base interface in order to propagate the transaction ID. As a result, it was impossible to have, for example, a transactional implementation of the naming service and a non-transactional one because that required incompatible type definitions for the same service. (A later revision of the CORBA transaction specification remedied this.)

    Contexts are not intended for application data, unless the use of the context data truly is along the same lines: you must have the data, but you cannot pass the data as an operation parameter because you must be able to use the same Slice operations with and without that data, and with different semantics. (You can think of the context data as parameters that are optional, either present or not present.)

    Exactly where you draw the line between implicit context parameters and explicit Slice parameters is really up to you and your application. But, for things such as authentication keys, contexts may be what you need.

    As an alternative, I would at least consider passing the information as an additional Slice parameter. If you have several items of data, you can group them into a Slice struct or class and pass that instead of several parameters. That way, you can strongly type each data item, and their existence is explicitly manifest in the Slice definition. With classes, you can also implement optional parameters, by deriving from a base class and declaring the parameter as the base type. The actual parameters are then passed as a derived class type.

    In summary, you should ask yourself whether the use of contexts really must be transparent. If you use contexts merely to avoid having an additional parameter on every operation, contexts are probably not the right thing. The key criterion (to me, at least) is whether the same interfaces must be usable with and without the context information. (For example, you build a service that works without this data now, but anticipate creating another version that requires the data later, and anticipate that both versions must be able to co-exist side by side.) If so, contexts are the right thing to use.

    Finally, keep in mind that, once you have started using contexts, you cannot make any change to a context (either in the name of the parameter or its type) without breaking the on-the-wire protocol. This is because, once an application relies on a context being there, any change to the name or type of the context is likely to break that application. However, there is nothing in the Slice definitions that would alert you to such an incompatibility--any problem will show up only at run time. This suggests that, if you anticipate any future change in the encoding or semantics of a context parameter, you should add a version identifier to the data for each parameter.

    Cheers,

    Michi.
  • Hi Michi,

    Thanks for the reply. That was exactly what I wanted to know. The distinctions you draw (eg. infrastructure vs. application; whether the data in the context has to be transparent) are very helpful.

    Cheers,
    Gary