Server-Side JavaScript Mapping for Interfaces

The server-side mapping for interfaces provides an up-call API for the Ice run time: by implementing member functions in a servant class, you provide the hook that gets control flow from the Ice server-side run time into your application code.

On this page:

Skeleton Types in JavaScript

On the client side, interfaces map to proxy types. On the server side, interfaces map to skeleton types. A skeleton is a type that conceptually has an abstract member function for each operation on the corresponding interface. For example, consider our Slice definition for the Node interface:

Slice
module Filesystem
{
    interface Node
    {
        idempotent string name();
    }
    // ...
}

The Slice compiler generates the following definition for this interface:

JavaScript
class Node extends Ice.Object
{
    constructor(){ ... }
}
TypeScript
abstract class Node extends Ice.Object
{
    abstract name(current:Ice.Current):PromiseLike<string>|string;
}


The important points to note here are:

  • As for the client side, Slice modules are mapped to JavaScript scopes with the same name, so the skeleton definitions are part of the Filesystem scope.
  • For each Slice interface <interface-name>, the compiler generates a JavaScript type <interface-name> (Node in this example). This type extends Ice.Object and serves as the actual skeleton; it is the base type from which you derive your servant implementation.

Servant Types in JavaScript

In order to provide an implementation for an Ice object, you must create a servant type that inherits from the corresponding skeleton. For example, to create a servant for the Node interface, you could write:

JavaScript
class NodeI extends Filesystem.Node
{
    constructor(name)
    {
        this._name = name;
    }

    name(current)
    {
        return this._name;
    }
}
JavaScript
class NodeI extends Filesystem.Node
{
    constructor(name:string)
    {
        this._name = name;
    }

    name(current:Ice.Current)
    {
        return this._name;
    }


    _name:string;
}


By convention, servant types have the name of their interface with an I-suffix, so the servant type for the Node interface is called NodeI. (This is a convention only: as far as the Ice run time is concerned, you can choose any name you prefer for your servant types.) Note that NodeI extends Filesystem.Node, that is, it derives from its skeleton.

Here we're using JavaScript classes to define our servant. But as far as Ice is concerned, the NodeI type must implement only a single function: the name method defined by the Slice interface. You can add other methods and data members as you see fit to support your implementation. For example, in the preceding definition, we added a _name member and a constructor. (Obviously, the constructor initializes the _name member and the name method returns its value.) You can ignore the current parameter for now.

Normal and idempotent Operations in JavaScript

Whether an operation is an ordinary operation or an idempotent operation has no influence on the way the operation is mapped. To illustrate this, consider the following interface:

Slice
interface Example
{
    void normalOp();
    idempotent void idempotentOp();
    idempotent string readonlyOp();
}

The corresponding servant methods look like this:

JavaScript
class ExampleI extends Example
{
    normalOp(current){ ... }
    idempotentOp(current){ ... }
    readonlyOp(current){ ... }
}
TypeScript
class ExampleI extends Example
{
    normalOp(current:Ice.Current){ ... }
    idempotentOp(current:Ice.Current){ ... }
    readonlyOp(current:Ice.Current){ ... }
}


Note that the signatures of the member functions are unaffected by the idempotent qualifier.

See Also