Parameter passing on the server side follows the rules for the client side. Additionally, every operation receives a trailing parameter of type
Current. For example, the
name operation of the
Node interface has no parameters, but the corresponding
name method of the servant interface has a single parameter of type
Current. We will ignore this parameter for now.
The parameter-passing rules change somewhat when using the asynchronous mapping.
On this page:
Server-Side Mapping for Parameters in Java
The servant mapping for operations is consistent with the proxy mapping. To illustrate the rules for the Java mapping, consider the following interface:
The generated skeleton interface looks like this:
You'll notice that
op2 have same signature because the mapping rules state that an operation returning a single value shall use that type as its return value, regardless of whether the Slice operation declared it as the return type or as an out parameter. (The same is true for
op5.) The proxy and servant methods also share the
Result types that are generated when an operation returns more than one value, as shown above for
op6. When at least one of the return value and
out parameters is optional, the
Result type provides two overload constructors that takes the return value followed by all
out parameters: one with the
java.util.Optional types, and one without
java.util.Optional types; with the latter, a null value for an optional parameter is interpreted as meaning "not set".
The only difference between the client and server sides is the type of the extra trailing parameter.
Thread-Safe Marshaling in Java
The marshaling semantics of the Ice run time present a subtle thread safety issue that arises when an operation returns data by reference. For Java applications, this can affect servant methods that return instances of Slice classes, structures, sequences, or dictionaries.
The potential for corruption occurs whenever a servant returns data by reference, yet continues to hold a reference to that data. For example, consider the following servant implementation:
Suppose that a client invoked the
getGrid operation. While the Ice run time marshals the returned array in preparation to send a reply message, it is possible for another thread to dispatch the
setValue operation on the same servant. This race condition can result in several unexpected outcomes, including a failure during marshaling or inconsistent data in the reply to
getGrid. Synchronizing the
setValue operations would not fix the race condition because the Ice run time performs its marshaling outside of this synchronization.
Solution 1: Copying
One solution is to implement accessor operations, such as
getGrid, so that they return copies of any data that might change. There are several drawbacks to this approach:
- Excessive copying can have an adverse affect on performance.
- The operations must return deep copies in order to avoid similar problems with nested values.
- The code to create deep copies is tedious and error-prone to write.
Solution 2: Copy on Write
Another solution is to make copies of the affected data only when it is modified. In the revised code shown below,
_grid with a copy that contains the new element, leaving the previous contents of
This allows the Ice run time to safely marshal the return value of
getGrid because the array is never modified again. For applications where data is read more often than it is written, this solution is more efficient than the previous one because accessor operations do not need to make copies. Furthermore, intelligent use of shallow copying can minimize the overhead in mutating operations.
Solution 3: Marshal Immediately
Finally, a third approach is to modify the servant mapping using metadata in order to force the marshaling to occur immediately within your synchronization. Annotating a Slice operation with the
marshaled-result metadata directive changes the signature of the corresponding servant method, but only if that operation returns one or more of the mutable types listed earlier. The metadata directive has the following effects:
- For an operation
opthat returns multiple values and at least one of those values has a mutable type, the name of the generated
OpMarshaledResultinstead and the return type of the servant method becomes
- For an operation
opthat returns a single value whose type is mutable, the Slice compiler generates an
OpMarshaledResultclass and the return type of the servant method becomes
- The constructor for
OpMarshaledResulttakes an extra argument of type
Current. The servant must supply the
Currentin order for the results to be marshaled correctly.
The metadata directive also affects the asynchronous mapping but has no effect on the proxy mapping, nor does it affect the servant mapping of Slice operations that return
void or return only immutable values.
You can also annotate an interface with the
marshaled-result metadata and it will be applied to all of the interface's operations.
After applying the metadata, we can now implement the
Grid servant as follows:
Here are more examples to demonstrate the mapping:
Review the generated code below to see the changes that the presence of the metadata causes in the servant method signatures: