Previous Up Next

Chapter 10  Objects by value

omniORBpy supports objects by value, declared with the valuetype keyword in IDL. This chapter outlines some issues to do with using valuetypes in omniORB. You are assumed to have read the relevant parts of the CORBA specification, specifically chapters 4 and 5 of the CORBA 2.6 specification, and section 1.3.10 of the Python language mapping, version 1.2.

10.1  Features

omniORB supports the complete objects by value specification, with the exception of custom valuetypes. All other features including value boxes, value sharing semantics, abstract valuetypes, and abstract interfaces are supported.

10.2  Value sharing and local calls

When valuetypes are passed as parameters in CORBA calls (i.e. calls on CORBA objects declared with interface in IDL), the structure of related values is maintained. Consider, for example, the following IDL definitions (which are from the example code in src/examples/valuetype/simple:

module ValueTest { valuetype One { public string s; public long l; }; interface Test { One op1(in One a, in One b); }; };

If the client to the Test object passes the same value in both parameters, just one value is transmitted, and the object implementation receives a copy of the single value, with references to it in both parameters.

In the case that the object is remote from the client, there is obviously a copying step involved. In the case that the object is in the same address space as the client, the same copying semantics must be maintained so that the object implementation can modify the values it receives without the client seeing the modifications. To support that, omniORB must copy the entire parameter list in one operation, in case there is sharing between different parameters. Such copying is a rather more time-consuming process than the parameter-by-parameter copy that takes place in calls not involving valuetypes.

To avoid the overhead of copying parameters in this way, applications can choose to relax the semantics of value copying in local calls, so values are not copied at all, but are passed by reference. In that case, the client to a call will see any modifications to the values it passes as parameters (and similarly, the object implementation will see any changes the client makes to returned values). To choose this option, set the copyValuesInLocalCalls configuration parameter to zero.

10.3  Value factories

As specified in section 1.3.10 of the Python language mapping (version 1.2), factories are automatically registered for values with no operations. This means that in common usage where values are just used to hold state, the application code does not need to implement and register factories. The application may still register different factories if it requires.

If the IDL definitions specify operations on values, the application is supposed to provide implementations of the operations, meaning that it must register suitable factories. If the application chooses to ignore the operations and just manipulate the data inside the values, omniidl can be asked to register factories for all values, not just ones with no operations, using the -Wbfactories option.

The Python language mapping says a value factory should be “a class instance with a __call__ method taking no arguments”. omniORBpy is less restrictive than that, and permits the use of any callable object, in particular the value implementation class itself.

10.4  Standard value boxes

The standard CORBA.StringValue and CORBA.WStringValue value boxes are available to application code. To make the definitions available in IDL, #include the standard orb.idl.

10.5  Values inside Anys

Valuetypes inserted into Anys cause a number of interesting issues. Even when inside Anys, values are required to support complete sharing semantics. Take this IDL for example:

module ValueTest { valuetype One { public string s; public long l; }; interface AnyTest { void op1(in One v, in Any a); }; };

Now, suppose the client behaves as follows:

v = One_impl("hello", 123) a = CORBA.Any(ValueTest._tc_One, v) obj.op1(v, a)

then on the server side:

class AnyTest_impl: ... def op1(self, v, a): v2 = a.value() assert v2 is v

This is all very well in this kind of simple situation, but problems can arise if truncatable valuetypes are used. Imagine this derived value:

module ValueTest { valuetype Two : truncatable One { public double d; }; };

Now, suppose that the client shown above sends an instance of valuetype Two in both parameters, and suppose that the server has not seen the definition of valuetype Two. In this situation, as the first parameter is unmarshalled, it will be truncated to valuetype One, as required. Now, when the Any is unmarshalled, it refers to the same value, which has been truncated. So, even though the TypeCode in the Any indicates that the value has type Two, the stored value actually has type One. If the receiver of the Any tries to pass it on, transmission will fail because the Any’s value does not match its TypeCode.

In the opposite situation, where an Any parameter comes before a valuetype parameter, a different problem occurs. In that case, as the Any is unmarshalled, there is no type information available for valuetype Two, so omniORBpy constructs a suitable type based on the transmitted TypeCode. Because omniORBpy is unable to know how (and indeed if) the application has implemented valuetype One, the generated class for valuetype Two is not derived from the application’s One class. When the second parameter is unmarshalled, it is given as an indirection to the previously-marshalled value inside the Any. The parameter is therefore set to the constructed Two type, rather than being truncated to an instance of the application’s registered One type.

Because of these issues, it is best to avoid defining interfaces that mix valuetypes and Anys in a single operation, and certainly to avoid trying to share plain values with values inside Anys.


Previous Up Next