|
Articles Index |
Jini Index |
Wireless Initiative
By Bill Venners; Reprinted from JavaWorld
(November 1999)
This article gives you a glimpse of the Jini community in action and looks at what the serviceui project from Jini.org
has proposed for a standard way to attach a user interface to a Jini service.
Discussing Service UIs on the Jini-users Mailing List
My experience with Jini service UIs began back in January, when I posted
the following query to the Jini-users mailing list
(see Resources):
|
"Where will a user interface usually reside in service items? The service
object itself could be an applet, the service item could have methods
that put up the UI, or you could attach one or more applets as attributes.
If a service has a UI that must be used every time the service is used,
would you prefer to make the service object itself an applet, keep the
UI separate from the service object and enter all applets as attributes,
or invoke a method that puts up a UI?
Or, I suppose, will there be a preference? It seems the
"community" will need to develop guidelines on how you should architect
service items, and how clients should behave when presented with
different types of service objects and service items.
Any ideas?
bv"
|
The first reply to appear on the list was from Brian Jeltima of Sun
Microsystems:
|
"In my opinion, the GUI should rarely (I'd like to say never) be an
integral part of the service object. I think of the service as a protocol
defined via interfaces. A default user or management GUI can be attached
as an attribute, but the user of the service is free to interact with the
protocol directly and avoid the download of these bundled GUI objects if
they are not needed.
I imagine that a preferred approach will evolve rather quickly as device
manufacturers will be burning their solutions into ROM. The difficulty of
changing code in consumer devices will prompt them to think through these
issues early on, I would hope.
Brian"
|
Brian's post was followed by 16 others discussing how to attach a UI to a
service. I read all of these posts and then tried to summarize them on
the Jini-users FAQ as an answer to the question: Where in the service
item should I put the UI for my service? Here's a snippet from that answer,
which describes how I think a UI object would get a reference to the Jini
service object:
|
"Your factory instantiates and returns a UI object. The [UI object]
you write must accept a reference to the service object in its constructor.
This reference will be stored in a local variable, so the [UI object]
can use it. The [UI object] serves as an intermediary between the user
and the service."
|
(For a complete record of this first attempt to show how to add a UI to a
service, see the answer to question 14 on an
early version of the Jini-users FAQ.)
In response to my service UI answer, Jeltima made the following comment,
which describes his concern about my recommendation that a service object
reference be passed to the UI object constructor:
"The problem with passing the service object in the constructor is that
if the implementor decides to actually provide the GUI as a serialized
object in an attribute, then, when the client deserializes the GUI, the
constructor won't be called.... So I think [passing a service object
reference to] a separateinit() function [of the UI object]
is a bit more general [than passing a service object reference to the UI
object's constructor.]"
|
I thought Brian's comment made sense, but as I was very busy with other
things, my FAQ answer remained relatively unchanged for the next several
months.
Discussing Service UI at the Jini Community Summit
At the Jini summit last May in Aspen, CO, however, the issue of attaching
a UI to a service was revisited. During his presentation called "Creating
and Building New Jini Services," Jon Bostrom of Sun said that it was
important that someone define a standard way of attaching a UI to a
service.
Most people at the presentation agreed. I also voiced my agreement and
described January's Jini-users discussion and the resulting FAQ answer.
I also mentioned Jeltima's preference of using an init()
method rather than a constructor to pass a service object reference to a
UI object. I said, "If I do it my way and Brian does it his way, then
clients will have to know about both ways to offer UIs to each of our
Jini services." I also added that if no standard way of attaching a UI
to a service became generally accepted, service providers would attach
UIs independently and clients would need to know 500 different ways to
look for a service UI.
Unfortunately, I discovered as I was writing this article that the
example I gave at the Jini summit was wrong. As I myself had noted in
the first FAQ proposal, the UI object was being created and returned by
a factory method. A factory method is meant to hide from the client the
way an object (in this case, the UI object) is instantiated. Because the
factory method is responsible for initializing the new UI object, only
the factory method not the client needs to worry about whether to
pass a service object reference to a constructor, an init()
method, or some other method. Nevertheless, the attendees of Bostrom's
meeting seemed to accept my conclusion that even minor differences in the
way UIs are attached to services can complicate programming Jini clients.
In the end, we all agreed that defining a standard made sense, and that
the Jini community was the one to tackle the problem. Bostrom said that
while he'd be happy to have his team work on the approach, he thought it
would be best if someone who was not from Sun started it.
Later that day, another Sun employee slipped me this note:
|
"Bill,
On Jini.org, we can now create "projects." This may be a possible forum
for the GUI working group that we were all discussing in the "Jini
Services" breakout session."
|
A few days later, Ken Arnold of Sun posted this message to the Jini-users
mailing list:
|
"We have added a new feature to the Jini.org Web site you can create
collaborative projects for shared development of Jini service definitions,
development utilities, clients, documentation, and so forth.
Suppose you want to work on the correct design for GUI attributes (a
popular discussion among Jini users). You can go to the projects page on
Jini.org and see if someone is already working on it. If not, you can
create a new project...."
Ken
|
Creating the Serviceui Project
I must have subconsciously taken Bostrom's and Arnold's comments as
hints, because soon after this message was posted, I created a project on
Jini.org called serviceui. I did this partly because the message that Sun
wanted someone external to start the project had been firmly imprinted on
my brain, partly because a personal experiment in chaos I mean,
democracy seemed intriguing, and partly because it was so fast and
easy to create a project at Jini.org that I didn't think much about it
before creating it.
Shortly after creating the serviceui project, however, I had a minor panic
attack. What business did I have starting this project? Shouldn't I have at
least posted a query to the Jini-users list to build a consensus before acting
like some trigger-happy cowboy? Time, however, calmed my anxieties. Over the
next few weeks, many people joined the project and an interesting and fruitful
discussion commenced on the serviceui mailing list.
So far, the project felt like a group of engineers sitting in a virtual
conference room, discussing a design problem, and homing in on a solution.
I have served as scribe, attempting to capture the consensus in writing.
(Our current proposal forms the bulk of this article.)
I believe that in general the serviceui experiment has been successful. Our
main problem has simply been that because no one is getting paid and we are
all busy, our work has gone slowly. Nevertheless, we have made quite a bit of
progress. Hopefully, our work will be timely enough to do some good. One of
your most important goals when trying to establish a de facto standard is to
define it as early as possible, before people invest too heavily in other
approaches.
I hope to get a solid proposal by the next Jini summit, to be held in
Annapolis, MD, in October (see Resources.) Someone
from the project, perhaps myself, will present the proposal at the summit.
I'll now give you the serviceui project's current working proposal.
Any feedback you have is welcome. You can submit comments to my usual
discussion forum at Artima.com. Or you
can join the serviceui project at Jini.org and post comments to its mailing
list.
How to Add a UI to a Jini Service
As a general rule, you should not make a Jini service object extend a class
from a user interface library, such as Panel or JPanel.. Think of the service object as the way clients interact with a service
through the well-known Java interfaces that the service object implements.
To associate a UI with a service, use attributes.
You can associate many UIs with a service by placing entries for the UIs in
the service item's attributes. One reason to keep the UI separate from the
service object is that services may be used in devices that don't have user
interface libraries available. If you attach a UI to a service item as
attributes, those clients who have user interface libraries can retrieve your
UI and display it. Clients who don't have them can just use your service
object directly.
Each UI is represented by one UI object, which may or may not represent a
graphical UI component. A UI object could represent a voice-only interface, a
text interface, a combination of voice and graphics, a 3D-immersible world,
and so on. Each distinct kind of UI, including a 3D-immersible world with
voice and a virtual-text display, would be represented in the attributes by
one UI object.

Figure 1. Client code talks to a service through the Jini interface
Think of a service UI object as a type of "human adapter" an object that
sits between the Java interface offered by the service object and a human who
wants to use the service. Often a client program looks up a Jini service by
Jini interface type. As shown in Figure 1, such client programs can use the
service object directly by invoking methods in the service object's Jini
interface. The service object's Java interface must provide access to all
the service's functionality. Thus, a UI object merely serves as a go-between.
As shown in Figure 2, a UI object gives a human user access to the service
functionality via the Jini service interface.

The current working proposal gives four steps for adding a UI to a service.
The user will:
- Define a factory object
- Pass the service object to the UI
- Place the
UIFactory in an Entry
- Have the service object implement
Identifiable (optional)
Step 1. Define a Factory Object
To add a UI as an attribute, create a factory object with a method that
instantiates and returns a new UI object. This approach lets you make UI
objects available without requiring that they get serialized and stored in
the lookup service. You only need to serialize and store the factory-object
attribute and its enclosing entry in the service.
The UIFactory Interface
The factory object will need to implement a well-known UI factory interface
(and the serviceui project should propose one). Here's an example of what the
interface might look like:
// In file UIFactory.java
package org.jini.ui;
public interface UIFactory extends
java.io.Serializable {
Object getUI(Object serviceObject)
throws UICreationException;
}
|
Note that the package prefix org.jini.ui is used here to
represent whatever package prefix the community eventually decides upon.
Please do not use this package prefix. The org.jini package
space is controlled by the Jini community, which hasn't given anyone
permission to use org.jini.ui.
Exceptions Thrown by getUI()
A factory object's getUI() method may throw the following
two exceptions: InvalidServiceClassException
andUICreationException. The unchecked
InvalidServiceClassException will be thrown by
getUI() if it cannot cast the passed reference to the expected
service object class.
// In file InvalidServiceClassException.java
package org.jini.ui;
public class InvalidServiceClassException
extends RuntimeException {
public InvalidServiceClassException() {
}
public InvalidServiceClassException(
String msg) {
super(msg);
}
}
|
The checked UICreationException will be thrown by
getUI() if the factory cannot produce the UI object. If an
exception thrown by the UI object's constructor detects this problem, a
reference to that exception should be passed to the constructor of
UICreationException. This enables clients to retrieve the
original exception by invoking getThrownException() on the
caught UICreationException.
// In file UICreationException.java
package org.jini.ui;
public class UICreationException
extends Exception {
private Exception thrownException;
public UICreationException() {
}
public UICreationException(
String msg) {
super(msg);
}
public UICreationException(
Exception e) {
thrownException = e;
}
public Exception getThrownException() {
return thrownException;
}
}
|
2: Defining a Concrete Factory Class
To add a UI to a service, you must create a concrete class that
implements the UIFactory interface, such as:
/*
* PrinterJPanelFactory -
* An implementation of the UIFactory
* interface that knows to cast the service
* object to type PrinterService
* and instantiates and returns a
* new PrinterJPanel GUI object.
*/
package com.artima.printer;
import org.jini.ui.UIFactory;
import org.jini.ui.InvalidServiceClassException;
import org.jini.ui.UICreationException;
import org.printerfolks.PrinterService;
public class PrinterJPanelFactory
implements UIFactory {
public Object getUI(
Object serviceObject)
throws UICreationException {
PrinterService ps;
try {
ps = (PrinterService)
serviceObject;
}
catch (ClassCastException e) {
throw new
InvalidServiceClassException();
}
try {
return new PrinterJPanel(ps);
}
catch (Exception e) {
throw new UICreationException(e);
}
}
}
|
Each UI factory class knows the type of service object that should be
passed to its getUI() method. The first thing every
getUI() method should do is attempt to cast the passed object
to the expected type. If the cast doesn't succeed, the client has passed in
an inappropriate object and the method should throw the unchecked
InvalidServiceClassException. Otherwise, the getUI()
method should attempt to create the UI object, passing the reference to the
service object to the UI object's constructor. If any exception is thrown,
the getUI() method should create and throw a new
UICreationException, encapsulating the original exception inside
the UICreationException.
Step 2. Pass the Service Object to the UI
Your factory (shown above) instantiates and returns a UI object, in this
case, a JPanel. The JPanel you write must accept a
reference to the service object in its constructor. The reference will be
stored in an instance variable of the JPanel object, so that the
JPanel can interact with the service. The JPanel
can then serve as an intermediary between the user and the service. Here's an
example:
/*
* PrinterJPanel - A GUI panel that
* allows the user to interact with
* a printer across the network via a
* Jini service object
*/
package com.artima.printer;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.accessibility.*;
import java.awt.*;
import java.awt.event.*;
import org.jini.ui.*;
import org.printerfolks.*;
public class PrinterJPanel
extends JPanel {
private PrinterService serviceObject;
//...
public PrinterJPanel(
PrinterService serviceObject) {
this.serviceObject = serviceObject;
//...
}
//...
}
|
Step 3. Place the UIFactory in an Entry
Lastly, you must place your factory object in an entry so that it can be
attached to the service item. Eventually, you should be able to use well-known
entry classes to hold your UI factory attributes. All UI factory entry classes
will probably belong to a family of classes rooted on a class, like
UIFactoryEntry, shown here:
// In file UIFactoryEntry.java
package org.jini.ui.entry;
import net.jini.entry.AbstractEntry;
import java.util.Map;
public class UIFactoryEntry
extends AbstractEntry {
public String name;
public String function;
public UIFactory factory;
public Map properties;
UIFactoryEntry() {
}
UIFactoryEntry(String name,
String function, UIFactory factory,
Map properties) {
this.name = name;
this.function = function;
this.factory = factory;
this.properties = properties;
}
}
|
The name variable is a string that should be unique among the
UIFactoryEntry objects associated with each service item. You
use the name when searching for an appropriate UI from among the
UIs associated with a single service, as described later in this proposal.
The function variable indicates the UI's role. Some services may
have different UIs for different purposes and give them different function
names that indicate the purpose. Some examples are main for the
main UI, admin for an administration UI, and so on. The serviceui
project should establish recommended names for common functions and set
guidelines for service providers who want to use different function names.
The factory variable simply holds a reference to the UI factory
object that will produce the UI object.
The properties variable holds a Map that enables
service providers to associate with a UI (property objects) that describes the
UI. Clients can search through these properties to help them locate the most
appropriate UI object for their needs. A description of the process is
provided later in this proposal.
The inheritance relationships of UIFactoryEntry subclasses will
correspond to the inheritance relationships of the UI objects they generate.
For example, given that java.awt.Panel subclasses
java.awt.Component, the corresponding UI factory entries
would have a similar relationship. For example, PanelFactoryEntry
would subclass ComponentFactoryEntry. Here's how that might look:
// In file ComponentFactoryEntry.java
package org.jini.ui.entry.java.awt;
import org.jini.ui.UIFactoryEntry;
import java.util.Map;
public class ComponentFactoryEntry
extends UIFactoryEntry {
// Could add other public fields
// here that allow instances to
// characterize themselves in a way
// that can be selected by
// matching criteria in the
// ServiceTemplate passed to an
// invocation of lookup() on a
// ServiceRegistrar.
ComponentFactoryEntry() {
}
ComponentFactoryEntry(String name,
String function, UIFactory factory,
Map properties) {
super(
name, function, factory, properties);
}
}
// In file PanelFactoryEntry.java
package org.jini.ui.entry.java.awt;
import java.util.Map;
public class PanelFactoryEntry
extends ComponentFactoryEntry {
// Could add other public fields here
// that allow instances to
// characterize themselves in a way
// that can be selected by
// matching criteria in the ServiceTemplate
// passed to an invocation of lookup() on a
// ServiceRegistrar.
PanelFactoryEntry() {
}
PanelFactoryEntry(
String name, String function,
UIFactory factory,
Map properties) {
super(name, function, factory,
properties);
}
}
|
To avoid name conflicts, the package names of factory entry classes should
be composed of a to-be-chosen UI entry-package prefix (here,
org.jini.ui.entry), followed by a dot and the package name of
the UI object class that the factory generates. Thus, the package name for a
factory entry for javax.swing.JPanel would be
org.jini.ui.entry.javax.swing. This package-naming scheme
enables anyone to easily and immediately add a factory entry for a newly
invented UI object to the well-known UI entry package (here,
org.jini.ui.entry). You shouldn't worry that you will
interfere with someone else who happened to pick the same name, nor should
you have to apply to some committee that controls the namespace for UI
factory entries. If IBM invents a new UI object that combines voice and
graphics and gives it the fully qualified name
com.ibm.ui.vng.VoiceAndGraphics, it could immediately name
its UI factory entry VoiceAndGraphicsFactoryEntry and place
it in the org.jini.ui.com.ibm.ui.vng package.
The name field of each UIFactoryEntry associated
with a particular service should be unique. (In other words, the uniqueness
of these names need only be enforced among the attributes of each individual
service item.) The name field lets a client grab the
UIFactory object from a specific UIFactoryEntry
via the getFieldValues() method of the
ServiceRegistrar. You'll see an example of this later.
The function field of the JPanelFactoryEntry lets
different UI objects that serve different purposes be identified in an
attribute search. Possible names for functions are main and
admin. The serviceui project should define a set of standard
function strings.
The properties field contains a mapping from strings to
property objects that characterize the UI object. For example, you
might define a UI property object that describes the minimum screen
size on which a particular UI should be used:
// In file MinimumScreenSize.java
package org.jini.ui;
public class MinimumScreenSize
implements java.io.Serializable {
private java.awt.Dimension minScreenSize;
public MinimumScreenSize(
java.awt.Dimension dim) {
this.minScreenSize = dim;
}
public java.awt.Dimension
getMinimumScreenSize() {
return minScreenSize;
}
}
|
A MinimumScreenSize property could then be associated with
a UI object by adding it to the properties map of the UI's
entry object and associating it with a well-known key, such as
minscreensize. Clients could then inspect this property and others by searching in the map by their well-known keys. The UI's name and function are two properties that should sit in every map. (In other words, the information stored in the name and function fields of the UIFactoryEntry object should also appear in the properties map, perhaps under the keys name and function.) Properties, such as MinimumScreenSize, give information about particular UIs to facilitate client searches for the best UI for a situation. (Note that because of name and function, all entries should have a properties map.)
Step 4. Have the Service Object Implement Identifiable
(optional)
Service providers can attach any number of UIs to a service object by
including them in the service item as attributes. A service provider may
want to offer multiple UIs to accommodate clients who have different
capabilities and users who have different preferences. A service could
attach a Swing JPanel geared toward users sitting on a desktop,
an AWT Panel aimed at television screens and remote-control input devices, a
different AWT Panel for small PDAs with touch-sensitive screens, a UI object
that offers a voice-only user interface for telephone users, and so on. The
client must be able to search through the service's UI options easily and
quickly to find the best service that matches its capabilities and its user's
preferences.
To search for an appropriate UI object, a client with sufficient resources
can just use the ServiceMatches lookup(ServiceTemplate, int)
method of the ServiceRegistrar to retrieve the entire attribute
set of a service along with the service object and its ServiceID
object. It can then search through its local copies of all the attributes to
find an appropriate UI.
Many clients, however, will not want to download all the attributes. Those
attributes take up memory, which can be a scarce resource in a small consumer
device. In addition, downloading them may trigger unnecessary class files to
be downloaded as well. (The JVM specification lets implementations load
classes before they are used.) Such clients can use the
Object lookup(ServiceTemplate) method of
ServiceRegistrar, which, rather than returning an array of
matching ServiceItems, returns only one matching service object.
If more than one service matches the template passed to this
lookup() version, one is selected arbitrarily and
returned.
If such a resource-constrained client wants to display a UI for a service it
got from calling Object lookup(ServiceTemplate), it must search
through that service's attributes via methods declared in the
ServiceRegistrar interface. Unfortunately, the client won't
have enough information to uniquely identify the service whose object it
has a local copy of. To be certain it can uniquely identify the service, the
client needs the service's ServiceID. But when the client
invokes lookup(), it just gets the service object, not the
ServiceID. Thus, the only way this client can get the
ServiceID is by asking the service and invoking a method on the
service object.
For this reason, services that want to be friendly to resource-constrained
clients should implement the Identifiable interface, which lets
clients ask the service for its ServiceID:
package org.jini.ui;
import net.jini.core.lookup.ServiceID;
public interface Identifiable {
ServiceID getServiceID();
}
|
Note: As an alternative to Identifiable,
it might be a nice enhancement to the ServiceRegistrar
interface to add a method that returns one service object and its
associated ServiceID, but no attributes.
Use Cases
A Resource-Constrained Client
To find an appropriate UI for a service, a resource-constrained client
would:
- Get a service object
Client builds a ServiceTemplate that describes the service it
desires, and invokes Object lookup(ServiceTemplate) on a
ServiceRegistrar. The ServiceTemplate can include
one or more UIFactoryEntry objects; these help the search to
just the requested services that offer one or more UIs the client may
potentially use.
- Get the service ID
The client makes sure the service object implements
Identifiable with instanceof. If it does, the
client casts the service object reference to Identifiable,
and invokes getServiceID() on that reference. The client now
has the service ID.
Note that if the service object does not implement
Identifiable, the client has to use the other form of
lookup() to get an entire ServiceItem.
This consumes more resources, but it yields a local copy of all attributes,
which enables the client to search locally for an appropriate UI. Using this
alternative approach may not be practical (or possible) for a
resource-constrained client, which is why providers of services that these
clients can be expected to request should implement Identifiable.
- Retrieve property maps for candidate UIs
The client builds a ServiceTemplate composed of the
ServiceID object, which uniquely identifies the service, and an
instance of a subclass of UIFactoryEntry, which indicates
the desired UI type and potentially some desired UI characteristics. (For
example, if the client is interested in a java.awt.Panel, it
would create an instance of PanelFactoryEntry and put that in
the ServiceTemplate.)
Once the client has the ServiceTemplate, it invokes the
getFieldValues(ServiceTemplate tmpl, int setIndex, String field)
method on the ServiceRegistrar. In the tmpl
argument, it passes a reference to the ServiceTemplate. In
the setIndex argument, it passes zero (or whatever index the
UIFactoryEntry exists in the ServiceTemplate's
attr field). In the field argument, it passes the
string properties.
The client gets an array of Map objects as the return value of
the getFieldValues() method invocation. Each Map
object contains properties that characterize a UI whose entry matched the
type specified in the ServiceTemplate. The client can then use
the property maps to select an appropriate UI.
For example, if the client has a small screen size, it may look for a
minscreensize property in each Map, then compare
the minimum screen size properties to find the UI object that is most suitable
for the client's display capabilities. Other properties can include locales
that the UI directly supports, so a client with a French-speaking user can
find UIs that offer a French option. Any useful way to characterize a UI can
be given a well-known property name and added to the Maps that
sit in the UIFactoryEntry objects.
- Retrieve one
UIFactory
When the client decides which Map represents the best UI for its
needs, it looks up the name property on that Map.
The name property should contain a String with an
identical value to the String referenced by the name
field of the corresponding UIFactoryEntry subclass. For example,
if the name field of a JPanelFactoryEntry refers to
a String with the value Bob's Groovy UI, then you
should get a String with the value Bob's Groovy UI
when you look up the name property on the Map
contained in the properties field of that same
JPanelFactoryEntry.
Having retrieved the name property from the selected
Map, the client builds a new ServiceTemplate
composed of the ServiceID object and an instance of
UIFactoryEntry with the name field set to the
retrieved value of the name property. Then, the client once
again invokes getFieldValues() on the
ServiceRegistrar. It passes in its new ServiceTemplate
in the tmpl argument, the appropriate index (probably zero) in
the setIndex argument, and the String
factory in the field argument.
The name field of each UI factory-entry object in a particular
service item's attributes array should be unique. Thus, the
ServiceTemplate passed to the most recent invocation of
getFieldValues() should match only the one UI factory entry
that has the requested name. Therefore, getFieldValues() will
return one UIFactory object. This object generates the UI
object the client deemed to be most appropriate given its capabilities and
user's preferences.
- Create the UI
Lastly, the client simply invokes getUI() on the
UIFactory, passing in a reference to the service object.
The getUI() method returns a new UI object. Although the
type of reference is an object, the client can downcast that reference to
a more specific type. If the client is looking for a UI among
PanelFactoryEntrys, for example, it can downcast the reference
returned by the UIFactory to java.awt.Panel.
A Resource-Rich Client
To find an appropriate UI for a service, a resource-rich client could:
- Get a set of service items
Client builds a ServiceTemplate that describes
the service it desires, then invokes
Object lookup(ServiceTemplate, int) on a
ServiceRegistrar. The ServiceTemplate can
include one or more UIFactoryEntry objects to help narrow
the search to just the requested services that offer one or more UIs that
the client may potentially use.
- Search for an appropriate service and UI
This resource-rich client already has a set of matches for its query that
includes full information about matching services. The client can simply
search through this information to find an appropriate service and UI.
- Create the UI
Lastly, the client simply invokes getUI() on the chosen
UIFactory, passing in a reference to the chosen service object.
Discussion
To discuss the material presented in this article, including submitting
feedback about the serviceui proposal, visit the discussion forum at
Serviceui.
The small print: "How to attach a UI to a service" article
Copyright © 1999 Bill Venners. All rights reserved.
RESOURCES:
Serviceui: To comment about the current serviceui proposal, post at this forum:
Jini.org: Participate in the serviceui project
Community Meeting: For more information about the next Jini summit:
Book List: Recommended Jini technology books:
FAQ: A Jini FAQ for the JINI-USERS mailing list:
Resources: Links to Jini technology resources:
Releases: Download page for the current Jini release (at the Java Developer Cconnection)
JDK 1.2: Download page for JDK 1.2 FCS Release, on which the current Jini release runs
Tutorial: An online Jini technology tutorial
Notes: Online lecture notes for a course about RMI and Jini technology
Jini: The main Jini page at Sun Microsystems.
Jini.org: The Jini Community, the central site for signers of the Jini Sun Community Source License to Interact
Jini Specifications:
Download page for all of the Jini specifications
listserv@java.sun.com: Subscribe to the JINI-USERS mailing list by typing, subscribe jini-users, in the body of the message
List Archives: JINI-USERS mailing list archives

Reprinted with permission from the October 1999 edition of JavaWorld magazine. Copyright Web
Publishing Inc., an IDG Communications company.
Register for editorial e-mailalerts
About the Author
Bill Venners has been writing software professionally for 14 years. Based in Silicon Valley, he provides software consulting and
training services under the Artima Software Company.
He has developed software for the consumer electronics,
education, semiconductor, and life insurance industries. Bill has programmed in
many languages on many platforms: assembly language on various microprocessors,
C on Unix, C++ on Windows, Java on the Web. He wrote
Inside the Java 2.0 Virtual Machine,
(Enterprise Computing, October 1999).
|