Context Toolkit: Tutorial: Context Servers

Context servers are responsible for aggregating all the context about a particular entity: person, place, or object. We believe that entities are key to the notion of context. A server supports this aggregation behavior by taking on all of the behaviors (attributes, callbacks, and services) of relevant context widgets. It subscribes to all the widgets that you think are relevant (when resource discovery is added, the relevant widgets will be determined automatically). For example, a server representing a particular person should subscribe to any widget that can provide information about that person. A server essentially behaves as a mediator, with whom an application can talk to and get all the benefits of the widgets that it encompasses.

For ease of use of the context infrastructure, applications should talk to servers, rather than widgets - rationale is there will be fewer different components to talk to if dealing with servers instead of widgets. However, because most of the applications I've built so far use a small variety of context, they talk directly to the widgets. Use your best judgement as to whether it makes more sense to talk directly to the widgets or through a server(s). I will first discuss the features of context servers and then talk about how to actually use them. Also take a look at the source code documentation for the Server class.



Features

Servers subclass from Widgets, so they have all the features of Widgets. As well, they act as an aggregator of context about an entity and act as a mediator between applications and widgets.
Aggregator
A server subscribes to all the widgets that are relevant to the entity the server represents. If a storage mechanism has been set up for the server to use (one exists, by default), the server acts as a central repository for all the context known about its entity.
Mediator
A server subscribes to all the widgets that are relevant to the entity the server represents. When an application wants to poll for context, subscribe to context, or execute a particular service, it no longer needs to individually communicate with a widget, and instead, can talk to the relevant server. The server acts as a mediator to all the widgets that can provide relevant context information about the server's entity.

How to Use It

In this section, I'll discuss how to use existing servers and then how to create new servers.
Using Existing Servers
To use the existing context servers in the context.arch.server package, execute the server: "java context.arch.server.S???" with no parameters. The parameter list for the server should be printed out.

 In general, the minimum parameter list will include a port number for the server to receive communications on (although the server will likely have a default), an identifier for the server and the widgets that are relevant (hostname, port, and id for each). For example, the User server, which maintains all the context for a user, has the following parameter list: < name > [port] {widget_host widget_port, widget_id} . The name acts as the identifier, allowing multiple User servers to be deployed for users. The [...] means the parameter is optional, <...> means the parameter is mandatory, and {...} means that the set can be entered zero, one, or many times.

 The basic Server class subclasses the basic Widget class, and inherits all of its behaviors and methods. Therefore, an application or context component can communicate with the context server using the BaseObject class, exactly like I showed for widgets. It can:

When talking to a server, or any context component, you must have the hostname, port number, and id of the server. The id for a server is the classname without the preceding 'S', followed by '_', followed by the server's identifier. For example, to communicate with an instance of SUser with name "Anind", the id is "User_Anind".
Creating New Servers
The easiest way to create a new server, is to use an existing server from the context.arch.server package as a starting point. You can also look at the basic Server class documentation.

 When you want to create a new server, there are a set of steps that you must take:

The SUser class code will be referred to throughout this subsection. The code is available here.
Setting the CLASSNAME Constant
The id of a server is set to the type of server concatenated with the server's identifier. Specifically, it is set to CLASSNAME+"_"+identifier or CLASSNAME+SPACER+identifier. It allows other components to easily identify the server. Example code for the SUser class follows:
  /**
   * Name of server
   */
  public static final String CLASSNAME = "User";
Creating the Server's Constructor
The constructor must call the Server class' constructor, usually using this constructor that specifies the widget port number, id, and the widgets to subscribe to.

  public Server(int port,
                String id,
                WidgetHandles widgets)

The id should be set to CLASSNAME+SPACER+identifier. The constructor should set the version number using BaseObject's setVersion method. It should call the Server class' startSubscriptions method. This method subscribes to all the specified widgets and gets access to the attributes, callbacks and services of these widgets.

 Example code from the SUser class follows:

  /**
   * Constructor that creates a user server for the user name
   * on the specified port. This server monitors the set of widgets
   * in widgets with storage functionality set to storageFlag
   *  
   * @param name User name this server is attached to
   * @param port Port this server is listening on
   * @param widgets Set of widgets this server monitors
   * @param storageFlag Flag to indicate whether storage is enabled or not
   *
   */
  public SUser (int port, String name, boolean storageFlag, WidgetHandles widgets) {
    super(port, CLASSNAME+SPACER+name, storageFlag, widgets);
    username = name;
    setVersion(VERSION_NUMBER);
    startSubscriptions();
  }
The WidgetHandles object is a list of WidgetHandle objects, each of which contains a hostname, port, and id for a widget.

Server has a number of constructors. I'll describe the most generic. The other constructors are simplifications that eventually call this
constructor. The generic constructor is here.

  public Server(String clientClass,
                String serverClass,
                int serverPort,
                String encoderClass,
                String decoderClass,
                String storageClass,
                String id,
                WidgetHandles widgets)

Because Server inherits from Widget, it also has a pluggable storage mechanism. The default storage mechanism is to use JDBC (Java DataBase Connectivity) with the MySQL database. When a server is instantiated for the first time, it creates a table in the database to store its context. To use a different storage mechanism, simply provide the name of the class that implements the new mechanism, specified by the context.arch.storage.Storage interface. If the value null is provided for this clas, the default JDBC/MySQL implementation is used.

If storage is not desired at all, another generic constructor should be used.

  public Server(String clientClass,
                String serverClass,
                int serverPort,
                String encoderClass,
                String decoderClass,
                boolean storageFlag,
                String id,
                WidgetHandles widgets)

This is similar to the previous constructor, except rather than a storageClass being used, a storageFlag parameter is used. If the flag is
true, the default storage mechanism will be enabled. If the flag is false, the storage mechanism is turned off and the widget will not
store any data.

Specifying the Server's Attributes
The server already inherits all the attributes of the widgets it subscribes to. The specification being discussed is for any other attributes that the server wants to support, beyond those of the widgets. The extra attributes of the server must be specified using the Server class' setServerAttributes abstract method. A server must implement this method by simply returning an Attributes object that contains the attributes of the server.

 Example code from the SUser class follows:

  /**
   * This method sets the attributes for the server - those
   * that are specific to the server, and not contained in the widgets
   * it subscribes to.  Currently, there are none.
   *
   * @return Attributes object containing the server-specific attributes
   */
  protected Attributes setServerAttributes() {
    return new Attributes();
  }
Specifying the Server's Callbacks
The server already inherits all the callbacks of the widgets it subscribes to. The specification being discussed is for any other callbacks that the server wants to support, beyond those of the widgets. The extra callbacks of the server must be specified using the Server class' setServerCallbacks abstract method. A server must implement this method by simply returning an Callbacks object that contains the callbacks of the server.

 Example code from the SUser class follows:

  /**
   * This method set the callbacks for a server - those
   * that are specific to the server, and not contained in the widgets
   * it subscribes to.  Currently, there are none.
   *
   * @return Callbacks object containing the server-specific callbacks
   */
  protected Callbacks setServerCallbacks() {
    return new Callbacks();
  }
Specifying the Server's Services
The server already inherits all the services of the widgets it subscribes to. This means that it mediates the service execution. If a component requests a service be executed, the server passes the request to the appropriate widget and returns any result to the requesting component. The specification being discussed is for any other services that the server wants to support, beyond those of the widgets. The extra services of the server must be specified using the Server class' setServerServices abstract method. A server must implement this method by simply returning a Services object that contains the services of the server.

 Example code from the SUser class follows:

  /**
   * This method set the services for a server - those
   * that are specific to the server, and not contained in the widgets
   * it subscribes to.  Currently, there are none.
   *
   * @return Services object containing the server-specific services
   */
  protected Services setServerServices() {
    return new Services();
  }
Setting a Server's Conditions
A server is responsible for a particular entity, which means that it usually is not interested in all the context a widget can provide, but only a subset. The server can set a Conditions object which specifies the subset it is interested in, using the setConditions method. Example code from the SUser class follows:
  /**
   * This method sets the conditions to apply to the
   * server's subscriptions.  The condition for the User Server is
   * USERNAME='username'
   *
   * @return Conditions containing condition info for server subscriptions
   */
  protected Conditions setConditions() {
    Conditions conds = new Conditions();
    conds.addCondition(USERNAME,Storage.EQUAL,username);
    return conds;
  }

Useful Classes

This is a list of useful classes, that you'll be using when you deal with context servesr.
WidgetHandles
The WidgetHandles class is really a collection of individual WidgetHandle objects. Each WidgetHandle object is a container for information needed to communicate with a widget. This includes the widget's hostname, port number, and id.


Back to the Table of Contents.

Back to the Context Widgets section.
Forward to the Context Interpreters section.
Up to the Context Components section.



Context Toolkit Home
Last Modified: Feburary 11, 2000
Comments to: anind@cc.gatech.edu