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:
module Filesystem { interface Node { idempotent string name(); } // ... }
The Slice compiler generates the following definition for this interface:
class Node extends Ice.Object { constructor(){ ... } }
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 extendsIce.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:
class NodeI extends Filesystem.Node { constructor(name) { this._name = name; } name(current) { return this._name; } }
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:
interface Example { void normalOp(); idempotent void idempotentOp(); idempotent string readonlyOp(); }
The corresponding servant methods look like this:
class ExampleI extends Example { normalOp(current){ ... } idempotentOp(current){ ... } readonlyOp(current){ ... } }
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.