Traditionally, desktop applications have been designed with a user interface (UI) built into the application. The code for the UI of the application is often highly coupled to the code that implements the functionality of the application. 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 object architecture encourages a different way of thinking about UI and functionality:
A Jini service object should represent the pure functionality of the service, expressed via the methods of its object interface. The service object interface for a toaster service, for example, should express or model the pure functionality of the conceptual toaster service -- it should say "what it means to be a toaster." The service object should not supply any way for human users to access to the toaster service. Such access should be provided by a separate "UI object."
One reason for keeping UI out of the service object is that it enables clients to access the service without human intervention or supervision. Clients written by programmers who knew about the (potentially well-known or standard) interface of a particular service object can interact with a service directly. As shown in Figure 1, client code can interact with a service directly by invoking the methods in the service object interface. Such a client is called a "prior-knowledge" client, because the programmers of such a client had to know about (have prior knowledge of) the service object interface.
Prior-knowledge clients need not be completely devoid of a user. For example, a user could be using a device that acts in certain cases as a prior-knowledge client. Were the user to request that the device quickly print something, the device could go get a printer service object and directly invoke the (not quite yet) well-known
print() method on the printer service object, with no further intervention of the user. In this case, the device acts as a prior-knowledge client even though it has a user, because the programmers of the device had prior knowledge of the printer service object interface and used this knowledge when programming the device.
On the other hand, prior-knowledge clients can also operate entirely independently of human supervision or intervention. Such clients act as "autonomous agents," which decide for themselves when to enlist the help of services. When an autonomous agent uses a service, it invokes the methods offered by the service object interface directly. Thus, the programmers of an autonomous agent must have prior knowledge of the service object interfaces their agent uses.
When you design a Jini service, you should attempt to capture the entire functionality of the service in the service object interface. To access any aspect of the service you are providing, a prior-knowledge client should need only one thing: a reference to the service object. The service object should not include any code that defines a user interface to the service, just code that provides the functionality of the service on the conceptual level of method invocations.
To provide a user interface for the service, you should encapsulate the user interface code in a separate "UI object." As shown in Figure 2, a UI object grants a user access to a Jini service. Think of a service UI object as a "user adapter" -- an object that adapts the interface of the service object, which a human user can't interact with directly, into some form that a human user can interact with directly. Sitting between the interface offered by the service object and a human user that wants to use the service, a UI object grants a user access to a service.
A UI object can represent a graphical UI component, such as an AWT
Frame or Swing
JPanel, but need not. A UI object could also represent a speech interface, a text interface, a combination of speech and graphics, a 3D immersive world, even a semantic expression of the UI that provides input to a dynamic UI builder. (The UI object is called "UI object," rather than "GUI object" or "view object,", because the object is intended to be more general than just an object, such as a
JFrame, that represents a graphical user interface.) Any kind of Jini service UI, even a 3D immersive world with speech and a virtual text display, should be represented by a single UI object, which is distinct from the service object.
The programmers of clients that will be used by a human user need not have prior knowledge of all the services hosted by the client. A user can be shown a list of services compiled by browsing a lookup service. The user can select one, which the client downloads. Given a standard way to attach a UI to a Jini service, the client can select a UI and attach the UI to the service object. The user interacts with the UI, and the UI interacts with the service object. Thus, the programmers of the client need not have prior knowledge of a service when a UI and user are also present. Because the programmers of the UI had prior knowledge of the service object interface, the programmers of the client need only have prior knowledge of the standard way to find and select an appropriate UI associated with a service. In Figure 2, it is the UI code, not the client code, that talks to the service object interface directly.
Separating UI and functionality is a flexible way to architect Jini services, because the same service object can be used with more than one UI object. This enables the same service to be accessed from many different kinds of Jini-enabled computers and devices. Different devices have different user interface capabilities. For a given service, a service provider can create multiple UI objects, each of which is geared for a different set of capabilities, and associate them with the service. Third party developers can potentially create their own UI objects to supplement those provided by the service provider. Thus, a Jini service architecture in which functionality is separated from UI enables users to access a service via many different kinds of Jini-enabled devices.
A separation of UI and functionality also makes it possible to make a Jini service accessible to devices that are not Jini enabled. A device that can't host a Jini service object and UI object itself can ask a "service host" to host the service and to place a "protocol adapter" object between it and the service. As shown in Figure 3, a a non-Jini device talks to a protocol adapter via a network protocol. The protocol adapter talks to the service object. Similar to the way a user adapter adapts a service to a human user, a protocol adapter adapts a service to clients, including non-Java and non-Jini clients, that understand a particular protocol.
Jini service hosts could be deployed in a local area environments. Non-Jini clients could discover a nearby service host and ask it to host a service and protocol adapter. If no nearby service host exists, the non-Jini client could contact a distant service host with which it maintains a long-term relationship. Through service hosts and the appropriate set of protocol adapter objects, service providers oculd extend the reach of their Jini services to the non-Jini world.
As a general rule, service providers should not mix UI code with service object code. For example, a Jini service object should not extend a class from a user interface library, such as
javax.swing.JPanel. Nor should it contain dependencies on any kind of UI library. Jini services, therefore, should not be designed in the way that desktop applications have often been defined, with UI code intermingled with functionality. The Jini service object should encapsulate the functionality of the service, the whole functionality of the service, and nothing but the functionality of the service. Prior-knowledge Jini clients can just use the service object directly. Human users can access the service via a "user adapter" object, and non-Jini clients can access the service via a "protocol adapter" object.
To find out just how service providers and third parties should attach UIs to Jini services, and how clients can search for a best-fit UI, see the ServiceUI Project pages.
Note: This article did not appear in the Jiniology column at JavaWorld.
Have an opinion? Be the first to post a comment about this article.
Bill Venners is president of Artima Software, Inc. and editor-in-chief of Artima.com. He is author of the book, Inside the Java Virtual Machine, a programmer-oriented survey of the Java platform's architecture and internals. His popular columns in JavaWorld magazine covered Java internals, object-oriented design, and Jini. Bill has been active in the Jini Community since its inception. He led the Jini Community's ServiceUI project that produced the ServiceUI API. The ServiceUI became the de facto standard way to associate user interfaces to Jini services, and was the first Jini community standard approved via the Jini Decision Process. Bill also serves as an elected member of the Jini Community's initial Technical Oversight Committee (TOC), and in this role helped to define the governance process for the community. He currently devotes most of his energy to building Artima.com into an ever more useful resource for developers.