The Artima Developer Community
Sponsored Link

Version 1.1a
The ServiceUI API Specification
by Bill Venners

<<  Page 3 of 12  >>


1. Introduction

Traditionally, desktop applications are designed with a built-in user interface (UI). The code for the application's UI is often highly coupled to the code that implements the application's functionality. Over time, tentacles of UI code may burrow deep into functionality code, and tentacles of functionality code may burrow back into UI code. In the traditional desktop application, therefore, the UI code and functionality code are usually inseparable, married for all eternity.

Jini's service proxy architecture encourages you to think differently about UI and functionality:

A Jini service proxy should represent the service's pure functionality, expressed via the methods of its object interface. For example, the service proxy interface for a toaster service should express or model the conceptual toaster service's functionality -- the interface should say "what it means to be a toaster." The service proxy should not supply human access to the toaster service; a separate UI object should provide such access.

1.1. Direct-Use Clients

One reason for excluding the UI from the service proxy is to enable client programs (clients) to access the service without human intervention or supervision. Clients written by programmers who knew about a particular service proxy's (potentially well-known or standard) interface can interact with a service directly. As Figure 1 shows, client code can interact directly with a service by invoking the methods in the service proxy interface. Such a client is called a direct-use client, because its programmers, based on their knowledge of the service proxy interface, can write code that uses the service directly via that interface.

Figure 1. A "direct-use" client talks to a service through its object interface.

Direct-use clients need not be completely devoid of a user. For example, a user could operate a device that acts as a direct-use client in certain cases. If the user requested that the device save some data in a file, the device could acquire a storage service proxy and directly invoke methods on that object to save data in a file, without further user intervention. In this case, the user-operated device acts as a direct-use client of storage services, because the device's programmers had prior knowledge of the storage service proxy interface and used that knowledge to program the device to use those services directly.

On the other hand, direct-use clients can also function independently of human supervision or intervention. Such clients act as autonomous agents, which decide for themselves when to enlist a service's help. When an autonomous agent uses a service, it invokes the methods offered by the service proxy interface directly. Thus, an autonomous agent's programmers must have prior knowledge of the service proxy interfaces their agent uses. (Although the human programmer actually has the prior knowledge when he or she writes the client code, in this document the code itself will often be said to have prior knowledge.)

1.2. User Adapters

When you design a Jini service, you should attempt to capture the service's entire functionality in the service proxy interface. To access any aspect of your service, a direct-use client should only need a reference to the service proxy. The service proxy should not include any code that defines a user interface to the service, just code that provides the service functionality at the method invocation level.

To provide a user interface for the service, you should encapsulate the user interface code in a separate UI object. As Figure 2 shows, a UI object grants a user access to some aspect of a Jini service. Think of a service UI object as a user adapter -- an object that adapts a service proxy interface that a human user cannot interact with directly into one a human user can interact with directly. Sitting between the service proxy interface and a human user, a UI object can grant the user access to a service.

Figure 2. A user interacts with a service via a UI object.

A UI object can represent a graphical UI component, such as an AWT Frame or Swing JPanel, but doesn't necessarily need to be graphical. A UI object could also represent a speech interface, a text interface, a speech and graphic combination, or a 3D-immersive world. (The UI object is called UI object, rather than GUI object or view object, because the object represents UI components in general, not just graphical UI components.) Any kind of Jini Service UI, including a 3D-immersible world with speech and virtual text display, should be represented by a UI object, which is distinct from the service proxy.

One advantage of this architecture, in which UI and functionality are separated, is that you can associate multiple UIs with the same service. Associating multiple UIs with one service lets you tailor different UIs for clients that have particular UI capabilities, such as Swing or speech. Clients can then choose the UI that best fits their user interface capabilities. In addition, you may want to associate different UIs that serve different purposes, such as a main UI or an administration UI, with a service. Often, you may need to associate multiple UIs with one Jini service, where each UI has a particular purpose and targets a particular set of client capabilities.

1.3. Jini Service UIs

This specification standardizes how UI providers associate a UI (user adapter) object with a Jini service, and shows how client programs can find the best-fit UI among multiple UIs associated with the same service. To associate a UI with a Jini service, UI providers (primarily service providers, but also possibly third parties) must supply three items:

A UI factory is an object that has one or more factory methods that produce and return a UI object. A UI descriptor, an instance of net.jini.lookup.entry.UIDescriptor (UIDescriptor), serves as a container for the UI factory and other objects that describe the UI produced by the factory. Because UIDescriptor implements net.jini.core.entry.Entry (Entry), you can include a UIDescriptor in a Jini service item's attribute sets array, thereby associating the UI with the service. A UI descriptor contains four public fields:

The attributes, toolkit, and role fields' purpose is to describe the UI produced by the marshalled UI factory. Using these fields, clients can choose from multiple UIs associated with a service. Once they select a UI object, clients can use the other field, factory, to create the object.

To associate a UI with a Jini service, the UI provider must first fill a UI descriptor with a role String, a toolkit String, an attribute set, and a marshalled UI factory. The UI provider must then place the UI descriptor in the attribute sets of the Jini service's service item.

A UI's role indicates both its purpose and its role-related semantics. Each UI role is defined as a Java interface type, which UI objects playing that role implement. The role field references a String whose value is the role interface type's fully qualified name. For example, a net.jini.lookup.ui.MainUI role UI provides general access to a service. A net.jini.lookup.ui.AdminUI role UI enables a user to administer a service. Although most UI object semantics of interest to the client program are defined by the UI factory's return type, some semantics may be tied to the role. For example, for a role that represents a user dialog, the role interface might include methods that let the client determine the dialog's result.

The UI descriptor's attributes field holds a reference to a java.util.Set of serializable objects that contain information about the UI the descriptor represents. These objects can be of any class, so long as they are serializable. Clients can search through the attributes set for attribute types about which they have prior knowledge. The objects can then help the client decide whether or not to use the descriptor-represented UI. Several attribute classes, defined in the net.jini.lookup.ui.attribute package, are described later in this document.

The toolkit field facilitates matching when querying the Jini lookup service. For example, if a client seeks all services that have main UIs working with the Swing toolkit, it could form a net.jini.core.lookup.ServiceItem (ServiceItem) whose attributeSetTemplates array includes a UI descriptor template. If the UI descriptor template's factory and attributes fields are set to null, the role field is set to net.jini.lookup.ui.MainUI, and toolkit field is set to javax.swing, the lookup would only return services that have at least one main UI for Swing.

The factory field contains the UI factory object inside a MarshalledObject so that you can place the class files for the factory and the UI it produces in a different codebase than the service item containing the UI descriptor. By placing the class files for UI factories and UI objects in separate codebases than that of the service item, clients can download a service item without downloading all the JAR files containing those class files, most or all of which the client may never use. Only if the client attempts to use a UI will it need to unmarshal the UI factory; this would trigger the downloading of the JAR file containing the factory class files, and possibly the class files for the factory-generated UI.

To use a UI, a client program must have prior knowledge of both the UI factory type (including, of course, the UI object type returned by its factory methods) and the UI role type. These types define the UI object semantics, which client programmers must understand before they can write code to interact properly with the UI. A client doesn't need prior knowledge of all the attributes types that appear in the attributes set. To the extent the client has prior knowledge of the attribute types, it can use that knowledge to select an appropriate UI from multiple UIs associated with a service.

<<  Page 3 of 12  >>

Sponsored Links

Copyright © 1996-2018 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use