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.
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 you want to create a new server, there are a set of steps that you must take:
/** * Name of server */ public static final String CLASSNAME = "User";
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.
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(); }
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(); }
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(); }
/** * 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; }
Back to the Context
Widgets section.
Forward to the Context
Interpreters section.
Up to the Context
Components section.