Object Incarnation in JavaScript

Having created a servant such as the rudimentary NodeI type, you can instantiate the type to create a concrete servant that can receive invocations from a client. However, merely instantiating a servant is insufficient to incarnate an object. Specifically, to provide an implementation of an Ice object, you must take the following steps:

  1. Instantiate a servant class.
  2. Create an identity for the Ice object incarnated by the servant.
  3. Inform the Ice run time of the existence of the servant.
  4. Pass a proxy for the object to a client so the client can reach it.

On this page:

Instantiating a JavaScript Servant

Instantiating a servant means to allocate an instance:

JavaScript
const servant = new NodeI("Fred");

This code creates a new NodeI instance.

Creating an Identity in JavaScript

Each Ice object requires an identity. That identity must be unique for all servants using the same object adapter.

The Ice object model assumes that all objects (regardless of their adapter) have a globally unique identity.

An Ice object identity is a structure with the following Slice definition:

Slice
module Ice
{
    struct Identity
    {
        string name;
        string category;
    }
    // ...
}

The full identity of an object is the combination of both the name and category fields of the Identity structure. For now, we will leave the category field as the empty string and simply use the name field. (The category field is most often used in conjunction with servant locators.)

To create an identity, we simply assign a key that identifies the servant to the name field of the Identity structure:

JavaScript
const id = new Ice.Identity();
id.name = "Fred"; // Not unique, but good enough for now

Activating a JavaScript Servant

Merely creating a servant instance does nothing: the Ice run time becomes aware of the existence of a servant only once you explicitly tell the object adapter about the servant. To activate a servant, you invoke the add operation on the object adapter. Assuming that we have access to the object adapter in the _adapter variable, we can write:

JavaScript
this._adapter.add(servant, id);

Note the two arguments to add: the servant and the object identity. Calling add on the object adapter adds the servant and the servant's identity to the adapter's servant map and links the proxy for an Ice object to the correct servant instance in the server's memory as follows:

  1. The proxy for an Ice object contains (among other things) the identity of the Ice object. When a client invokes an operation, the object identity is sent with the request to the server.
  2. The object adapter receives the request, retrieves the identity, and uses the identity as an index into the servant map.
  3. If a servant with that identity is active, the object adapter retrieves the servant from the servant map and dispatches the incoming request into the correct member function on the servant.

Ice for JavaScript currently supports only dispatches over bidirectional connections. As a result, you never need to call activate on your object adapter in JavaScript; activate currently does nothing in JavaScript.


UUIDs as Identities in JavaScript

The Ice object model assumes that object identities are globally unique. One way of ensuring that uniqueness is to use UUIDs (Universally Unique Identifiers) as identities. Ice for JavaScript provides a helper function that we can use to create such identities:

JavaScript
const uuid = Ice.generateUUID();
console.log(uuid);

When executed, this code prints a unique string such as 5029a22c-e333-4f87-86b1-cd5e0fcce509. Each call to generateUUID creates a string that differs from all previous ones.

You can use a UUID such as this to create object identities. For convenience, the object adapter has an operation addWithUUID that generates a UUID and adds a servant to the servant map in a single step. Using this operation, we can create an identity and register a servant with that identity in a single step as follows:

JavaScript
this._adapter.addWithUUID(new NodeI("Fred"));

Creating Proxies in JavaScript

Once we have activated a servant for an Ice object, the server can process incoming client requests for that object. However, clients can only access the object once they hold a proxy for the object.

At present, Ice for JavaScript only supports server-side activity over bidirectional connections. There are two ways of using bidirectional connections:

  • In conjunction with a Glacier2 router, which requires very little additional code in the client aside from ensuring that the object adapter is correctly configured to use the router. This is the simplest and most common way of employing bidirectional connections.
  • Manually configuring a connection for bidirectional use.

The remaining discussion in this section applies when using a Glacier2 router.

Proxies and Servant Activation in JavaScript

The add and addWithUUID servant activation operations on the object adapter return a proxy for the corresponding Ice object. This means we can write:

JavaScript
const proxy = NodePrx.uncheckedCast(this._adapter.addWithUUID(new NodeI("Fred")));

Here, addWithUUID both activates the servant and returns a proxy for the Ice object incarnated by that servant in a single step.

Note that we need to use an uncheckedCast here because addWithUUID returns a proxy of type Ice.ObjectPrx.

Direct Proxy Creation in JavaScript

The object adapter offers an operation to create a proxy for a given identity:

Slice
module Ice
{
    local interface ObjectAdapter
    {
        Object* createProxy(Identity id);
        // ...
    }
}

Note that createProxy creates a proxy for a given identity whether a servant is activated with that identity or not. In other words, proxies have a life cycle that is quite independent from the life cycle of servants:

JavaScript
const id = new Ice.Identity();
id.name = Ice.generateUUID();
const o = this._adapter.createProxy(id);

This creates a proxy for an Ice object with the identity returned by generateUUID. Obviously, no servant yet exists for that object so, if we return the proxy to a peer and the peer invokes an operation on the proxy, the peer will receive an ObjectNotExistException.

See Also