In Section 34.5.1, we mentioned that it may not be a good idea to allow clients to control the object identity of the Ice objects they create. Here is the scenario from
Section 34.2 once more, re-cast in terms of our phone book application:
At this point, things are likely to go wrong: server B thinks that it has obtained the phone number of the original Fred, but that entry no longer exists and has since been replaced by a new entry for a different person (who presumably has a different phone number).
What has happened here is that Fred has been reincarnated because the same object identity was used for two different objects. In general, such reused object identities are a bad idea. For example, consider the following interfaces:
interface Process {
void launch(); // Start process.
};
interface Missile {
void launch(); // Kill lots of people.
};
Replaying the preceding scenario, if client A creates a
Process object called “Thunderbird” and destroys that object again, and client C creates a
Missile object called “Thunderbird”, when server B calls
launch, it will launch a missile instead of a process.
To be fair, in reality, this scenario is unlikely because it tacitly assumes that both objects are implemented by the same object adapter but, in a realistic scenario, the same server would be unlikely to implement both launching of processes and missiles. However, if you have objects that derive from common base interfaces, so objects of different types share the same operation names, this problem is real: operation invocations can easily end up in a destroyed and later recreated object.
Specifically, the preceding scenario illustrates that, when the Ice run time dispatches a request, exactly three items determine where the request ends up being processed:
If object identities are insufficiently unique, a request intended for one object can end up being sent to a completely different object, provided that the original object used the same identity, that both provide an operation with the same name, and that the parameters passed to one operation happen to decode correctly when interpreted as the parameters to the other operation. (This is rare, but not impossible, depending on the type and number of parameters.)
The crucial question is, what do we mean by “insufficiently unique”? As far as the call dispatch is concerned, identities must be unique only per object adapter. This is because the ASM does not allow you to add two entries with the same object identity; by enforcing this, the ASM ensures that each object identity belongs to exactly one servant. (Note that the converse, namely, that servants in ASM entries must be unique, is
not the case: the ASM allows you to map different object identities to the same servant, which is useful to, for example, implement stateless facade objects—see
Section 32.9.2.) So, as far as the Ice run time is concerned, it is perfectly OK to reuse object identities for different Ice objects.
Note that the Ice run time cannot prevent reuse of object identities either. Doing so would require the run time to remember every object identity that has ever been used, which does not scale. Instead, the Ice run time makes the application responsible for ensuring that object identities are “sufficiently unique”.
You can deal with the identity reuse problem in several ways. One option is to do nothing and simply ignore the problem. While this sounds facetious, it is a viable option for many applications because, due to their nature, identity reuse is simply impossible. For example, if you use a social security number as a person’s identity, the problem cannot arise because the social security number of a deceased person is not given to another person.
Another option is to allow identity reuse and to write your application such that it can deal with such identities: if nothing bad happens when an identity is reused, there is no problem. (This is the case if you know that the life cycles of the proxies for two different objects with the same identity can never overlap.)
The third option is to ensure that object identities are guaranteed unique, for example, by establishing naming conventions that make reuse impossible, or by using a UUID as the object identity (see
Section 32.4.4). This can be useful even for applications for which identity reuse does not pose a problem. For example, if you use IceGrid well-known proxies (see
Section 38.6), globally-unique object identities allow you to move a server to a different machine without invalidating proxies to these objects that are held by clients.
In general, we recommend that if an Ice object naturally contains a unique item of state (such as a social security number), you should use that item as the object identity. On the other hand, if the natural object identity is insufficiently unique (as is the case with names of phone book entries), you should use a UUID as the identity. (This is particularly useful for anonymous transient objects, such as session objects, that may not have a natural identity.)