The Artima Developer Community

FAQ for JINI-USERS Mailing List

Here are some questions frequently posted to the JINI-USERS mailing list:

    General Questions:
  1. What is Jini?
  2. What does "Jini" stand for?
  3. Where will Jini be useful?
  4. How is Jini licensed?
  5. Will Jini work with PersonalJava?
  6. Do clients need a priori knowledge to use a service?
  7. What is the difference between Jini and RMI?
  8. How do you find out the IP address of a Jini service?

    Jini Programming:
  9. Where can I get the Jini release?
  10. What version of Java does the Jini release require?
  11. Where can I get the Jini specifications?
  12. I'm a Jini newbie. How do I get started with Jini?
  13. How do I lookup a service?
  14. I've got a problem. What info should I include in my post?
  15. Where in the service item should I put the UI for my service?
  16. How can I start multiple Jini lookup services on the same machine?
  17. Why must Service IDs be universally unique and why must they be remembered after assigned?
  18. Can a client make persistent changes to the attributes of a service?
  19. To what extent is Jini dependent upon IP?
  20. How can I control the lease length granted by a lookup service when I register my service?
  21. How do I perform advanced searches during lookup?
  22. What is the difference between Jini and CORBA?
  23. Should Jini service interfaces extend Remote?
  24. Why does an application that exports an RMI remote object need to be able to load the stub class?
  25. How should I partition classes at the RMI codebase among jar and class files?
  26. How do I use entry beans in my Jini service attributes?
  27. How are lookups by type implemented?
  28. Is there a way to receive notification when new services register with a lookup service?
  29. Does the discovery protocol limit Jini within a single subnet?
  30. How are service IDs generated such that they can be globally unique?
  31. What are the ServiceRegistrar's browsing methods for, and how are they used?
  32. Why do I get com.sun.rmi.rmid.ExecOptionPermission exceptions when starting Jini?
If you have a question you think belongs in this FAQ, please e-mail Bill Venners at bv@artima.com.


What is Jini?

Jini is a set of APIs and runtime conventions that facilitate the building and deploying of distributed systems. Jini provides "plumbing" that takes care of common but difficult parts of distributed systems.

Jini consists of a programming model and a runtime infrastructure. By defining APIs and conventions that support leasing, distributed events, and distributed transactions, the programming model helps developers build distributed systems that are reliable, even though the underlying network is unreliable. The runtime infrastructure, which consists of network protocols and APIs that implement them, makes it easy to add, locate, access, and remove devices and services on the network.

For a detailed introduction to Jini, see:

http://www.artima.com/jiniology/intro.html


What does "Jini" stand for?

Jini isn't an acronym, so it doesn't stand for anything. Though, as Ken Arnold pointed out, it does function as an anti-acronym: "Jini Is Not Initials." It is pronounced the same as the word "genie," so it sounds like jee-nee, not jin-nee.


Where will Jini be useful?

Jini is intended to be of general use, applicable in a wide range of distributed systems environments. In the home, it can help simplify the job of "systems administration" sufficiently that non-sophisticated home owners will be able to compose and use a network of consumer devices. In the enterprise, it can make it easier for traditional systems administrators to manage a dynamic network environment.

Thus, the home and the enterprise are two major network environments where Jini may make sense, but Jini's potential is not limited to these environments. Basically, anywhere where there is a network, Jini could potentially provide the plumbing for the distributed systems running on that network. For example, networks are emerging in cars, which nowadays contain many embedded microprocessors. Were you to plug a new CD player into your car, Jini could, for example, enable the user interface for the CD player to come up on your car's dashboard.


How is Jini licensed?

Sun licenses the Jini source code through the "Sun Community Source Code License," or "SCSL," which is a cross between keeping things proprietary and giving everything away via an open source license. For more information, see:

http://sun.com/jini/

Also, check out The Jini Community, the central site for signers of the Jini Sun Community Source Licence to interact:

http://www.jini.org


Will Jini work with PersonalJava?

Currently Jini does not work with PersonalJava, because (among other reasons) Jini depends on 1.2 RMI, and the current release of PersonalJava doesn't support 1.2 RMI. Sun says they expect to release later this year a new version of PersonalJava that supports Jini.


Do clients need a priori knowledge to use a service?

To use a service, clients will in general have a priori knowledge of at least one "known" (or "well-known") Java interface that the service object implements. In other words, if a client program makes use of, say, a Jini storage service, the programmer of the client will usually know about a standard (or, "well-known") interface to storage services when the programmer writes the client program.

Clients will usually specify one or more Java interfaces as part of the search criteria when looking for services on a lookup service. This approach means that clients will definitely know how to use the services they find, because by definition they know (have a priori knowledge of) at least one Java interface through which they can interact with the service.

Currently, no "well-known" interfaces really exist. These interfaces will likely be defined by industry consortiums. For example, various manufacturers of printers have gotten together to define a hierarchy of interfaces for printing. As families of "well-known" interfaces come into the public domain, they will likely be described and made available at the Jini Community web site:

http://www.jini.org

Currently, two working groups are forming to define "well-known" interfaces for printing and storage services. For information about these and other efforts, visit the Jini Community web site.

Although in the general case, client programs will have a priori knowledge of well-known interfaces implemented by the service objects they use, they needn't always. If a service offers a user interface (UI) the client can display, and that UI is attached to the service in a "standard" way known to the client, the client need not have any a priori knowledge about that service. The client need only have a priori knowledge of where the UI might be stored (likely as an attribute in the service item). Once the client locates the UI, it can pass a reference to the service object to the UI and display it. The user can interact directly with the UI, which interacts with the service via the service object. Because the UI knows how to use the service object, the client doesn't have to.

The serviceui project at jini.org is currently working to define a well-known way for UIs to be attached to services. To find out more, join the serviceui mailing list at:

http://developer.jini.org:80/cgi-bin/subscribeform

(You'll have to log in as a Community member, which requires that you agree to the Sun Community Source License terms for Jini.)


What's the difference between Jini and RMI?

Jini is built on top of RMI, so Jini requires RMI. RMI does not, however, require Jini. RMI, which stands for Remote Method Invocation, enables clients to hold references to objects in other JVMs, to invoke methods on those remote objects, and to pass objects to and from those methods as parameters, return values, and exceptions. RMI's object-passing abilities include a mechanism that enables downloading of any required class files across the network to the JVM receiving the object. Jini enables the spontanteous networking of clients and services on a network. Jini makes extensive use of RMI's ability to send objects across the network.

Both Jini and RMI involve a kind of directory service. In the case of Jini, the directory is called the lookup service. In the case of RMI, it is called the registry. The Jini lookup service enables clients to get references to services, which arrive in the local JVM as a reference to a local service object that implements a service interface. Similarly, the RMI registry enables clients to get references to remote objects, which arrive in the local JVM as a reference to a local stub object that implements a remote interface. Despite these similarities, however, several significant differences exist between Jini lookup services and RMI registries.

In general, a client program requires more knowledge about the network to use RMI than Jini, because Jini provides a discovery protocol that enables clients to locate nearby lookup services without prior knowledge of their locations. RMI, by contrast, requires that a client already know where a remote object is installed. In addition, because Jini service providers can also use the discovery protocol to locate lookup services, they can make their services available to the local area network without prior knowledge of that network. Because of the discovery protocol, Jini is able to provide "spontaneous networking" or "plug and work" between devices. Because it lacks a discovery protocol, RMI is not quite so spontaneous.

Another significant difference between RMI and Jini is the difference between a service object and a stub object. Although Jini makes use of RMI to send objects around, the service object on which the client invokes methods need not be an RMI stub. The Jini service object could be an RMI stub, but it's not necessary. A Jini service object can use any network protocal, not just RMI, to communicate back to any server, hardware, or whatever may be across the network. Alternatively, a Jini service object could fully implement the service locally so that it need not do any communication across the network. In the case of RMI, stub objects will always use the RMI wire protocol to communicate across the network to the remote object. A designer of each service decides which (if any) protocol is used to communicate across the network between a service object local to a client and a remote server. This means that Jini effectively raises the level of abstraction of distributed systems programming from the network protocol level to the object interface level. Clients don't have to worry about protocols, they just talk to object interfaces.

The third significant difference between RMI and Jini is that Jini provides a much more expressive way to search for services in a lookup service than RMI provides to search for remote objects in a registry. Each remote object is associated in a registry with a character string name that is unique within that registry. Jini services are registered with a service identifier that is globally unique and permanently maintained by each service, a service object, and any number of attribute objects. Clients can look up a service by service identifier, by the Java type or types of the service object, and by wildcard and exact matching on the attributes. Whereas RMI requires that a client know the name under which a desired remote object was registered, Jini enables a client to just look for the type of service desired. The ability to search for services by Java type is another feature of Jini that supports spontaneous networking. If you enter a LAN environment for the very first time and you want to use a printer, you don't have to figure out what name a printer service was registered under; instead, you just look up the services that implement a well-known Printer interface. Lookup by type also ensures that Jini clients will know how to use whatever it is they get back from their query, because they had to know the about the type to do the query in the first place.

In summary, RMI's aim is to enable invocation of methods on objects in remote JVMs and to enable the sending and receiving of objects between JVMs as parameters, return values, and exceptions of those remote method calls. Jini's aim is to enable spontaneous networking of clients and services that happen to find themselves on a local network.


How do you find out the IP address of a Jini service?

In general, you can't obtain the IP address of a service from the lookup service. The service proxy is never unmarshalled in the lookup service, so it's impossible to inspect the proxy for IP addresses. Also, there is no requirement that the entity that registers the service must also be the entity that provides the service, so knowing who performed the join in the general case tells you nothing. Even after the client retrieves the service proxy, obtaining an IP address is not possible in general, because a smart proxy can be designed to completely hide the network implementation details from the client. In fact, the proxy can entirely implement the service locally, resulting in no IP address. Or, the proxy could contact several different servers at various IP addresses simultaneously or at different periods during its lifetime; this means that there could, in fact, be many IP addresses. If you are a service provider and want to provide clients with your IP address, you must explicitly give them a way to get at it. You could either register an attribute with your service that gives the IP address, or your service object could implement an interface that includes a method which returns the IP address.


Where can I get the Jini release?

You can download the Jini binaries and source from the Java Developer Connection at:

http://developer.java.sun.com/developer/products/jini

You must be a member of the Java Developer Connection to access this page. If you are not a member, you can become one for free. (Well, for almost free. You do have to fork over some information about yourself.)


What version of Java does the Jini release require?

As of January 26th, the Jini binaries work with the JDK 1.2 FCS release. If you downloaded the Jini binaries prior to January 26th, your Jini binaries will NOT work with JDK 1.2 FCS, but with JDK1.2b4.

Get JDK 1.2 FCS from:

http://java.sun.com/products/jdk/1.2/

Get JDK1.2b4 from the Java Developer Connection at:

http://developer.java.sun.com/developer/earlyAccess/jdk12/beta4

Jini will not work with any JDK release prior to JDK 1.2. It is built on top of many features, such as new features of RMI, that did not exist in the JDK prior to JDK 1.2.


Where can I get the Jini specifications?

You can download all of the Jini specifications from:

http://java.sun.com/products/jini/specs/


I'm a Jini newbie. How do I get started with Jini?

Once you download the Jini binaries and the appropriate JDK release (see above), you may wish to download some of these examples and try to get them to run:

The example code from Bill Venners' Jini/JavaSpaces talk, and instructions on getting it to compile and run, are available at:

http://www.artima.com/javaseminars/modules/Jini/CodeExamples.html

Eran Davidov posted some example code to JINI-USERS, and Ken Arnold made some modifications to get the code to run on UNIX. Eran then updated the code to work with JDK FCS 1.2. This revised version can be downloaded from:

http://www.artima.com/jini/resources/timeservice.html

Brian Murphy posted some beginner examples to JINI-USERS, which you can retrieve from the JINI-USERS archives at:

http://archives.java.sun.com/cgi-bin/wa?A2=ind9902&L=jini-users&F=&S=&P=925

A Jini tutorial is available online at:

http://pandonia.canberra.edu.au/java/jini/tutorial/Jini.xml

Online lecture notes for a course about RMI and Jini are at:

http://www.eli.sdsu.edu/courses/spring99/cs696/notes/index.html

Noel Enete's "Nuggets," which contain example code and detailed instructions, are a great way to get started running Jini:

http://www.enete.com/download/#_nuggets_


How do I lookup a service?

The ServiceRegistrar interface provides two overloaded lookup() methods with which you can do lookups. If you just want to get one service that matches the template, use this form:

public Object lookup(ServiceTemplate tmpl)
    throws java.rmi.RemoteException
If a service matches the template, you will receive back a reference to the service object. If no service matches the template, you'll get back a null reference. If more than one service matches the template, you'll just get back one service object chosen randomly from the matches.

If you want multiple matching service objects, or you want to know how many services total match a template, use this form:

public ServiceMatches lookup(ServiceTemplate tmpl, int maxMatches)
    throws java.rmi.RemoteException
This method will never return null, but will always return a ServiceMatches object. ServiceMatches objects have two public fields:
public int totalMatches;
public ServiceItem[] items;
If you just want to know how many services match a template, but don't want any service items back, invoke lookup() with maxMatches set to 0. You will get back a ServiceMatches object whose items field is null and whose totalMatches field indicates the total number of services that match the template.

If you want multiple service items, just indicate your maximum in the maxMatches field. You will get back a ServiceMatches object whose items field contains the array of matching service items up to your specified maxMatches. The totalMatches field will still indicate the total number of services that match the template, which may be greater than the length of the returned items array.


I've got a problem. What info should I include in my post?

To help those who would help you with your problem, include the following information in your post along with the description of your problem:


Where in the service item should I put the UI for my service?

As a general rule, you should not make the service object itself extend a class from a user interface library, such as Panel, JPanel, Applet, or JApplet. Think of the service object as the way clients interact with a service through the well-known Java interfaces the service object implements. To associate UI with a service, use attributes.

One reason to keep UI out of your service object is that it may be used in devices that don't have user interface libraries available. If you attach UI to a service item as attributes, those clients that have the user interface libraries available can retrieve your UI and display it. Those clients that don't have user interface libraries available, can just use your service object directly. You can therefore associate zero to many UIs with a service by placing entries in the attributes of the service's service item.

Each UI is represented by one UI object, which can but need not represent a graphical UI component. A UI object could represent a voice only interface, a text I/O interface, a combination of visual and text, a 3D immersive world, and so on. Each one of these UIs, even a 3D immersive world with voice and a virtual text display, would be represented in the attributes by one single UI object.

A "standard" way of attaching a UI to a service is being developed by the serviceui project at jini.org. You can read about their latest ideas here:

http://www.artima.com/jini/serviceui.html

To participate in, or just keep track of, the development of a recommended approach to adding UI to a service, including definition of well-known interfaces and classes, join a mailing list for the serviceui project at jini.org.


How can I start multiple Jini lookup services on the same machine?

The only fixed port defined by the Jini specifications is the port for multicast discovery. Because this is a multicast port (unlike broadcast and connection-based ports), multiple lookup services on the same machine should be able to share this port.

Multiple lookup service on the same machine must, however, have different unicast discovery/response ports. The "reggie" implementation of the lookup service, which comes with the Sun' Jini release, includes an API (the DiscoveryAdmin interface) that enables you to change the default port number. Also, the -admin GUI of the lookup service browser enables you to configure specific ports. Such changes will remain persistent. If you don't need consistent port numbers, you can just fire off several reggies on the same host, and all reggies except the first will automatically use a dynamically allocated port rather than the standard one for unicast discovery.


Why must Service IDs be universally unique and why must they be remembered after assigned?

Every Jini service is supposed to have a service ID that is globally unique. If a service has no service ID, it can receive one from a Jini lookup service by simply registering with a lookup service. Usually a service includes its service ID as part of the service item it sends to the lookup service when it is registered via the join process. Whenever a lookup service receives a service item that has no service ID, it assigns a new service ID to that service and sends the ID back to the service. The service is reponsible for remembering and using that same service ID forever after. In practice, Jini service providers (such as enabled devices) will likely come from the factory with service IDs already installed.

Services are required to maintain the same service ID throughout their lifetimes for several reasons. First, because a service always uses the same service ID, it can't be registered twice in the same lookup service. Every service registered in a lookup service has a unique service ID. If a service registers itself with a lookup service using a service ID that is being used by a service already registered in that lookup service, the already registered service will be replaced by the newly registering service. The lookup service interprets the newly registering service as a replacement (or new version) of the currently registered service with the same service ID.

Another reason services are required to always use the same service ID is that a client can determine that multiple services retrieved from multiple lookup services are actually the same service. If two services retrieved from two different lookup services have the same service ID, then those two services actually represent the same single service, which was registered in two different lookup services.

And lastly, a permanent service ID allows lookup services to be queried by service ID. Queries based on service ID allows enables clients to find exactly the service they are looking for, independent of service and attribute object equality. A service may be upgraded with a service object that no longer implements the same interfaces as the previous version. Similarly, a service may be upgraded with a new set of attributes that don't have the same types or values as the previous versions. Such new versions of a service may not match queries the matched the old version of the same service. Despite this potential for incompatible upgrades, clients (such as systems administrators who want to track a service's status) can easily lookup the service by Service ID. Because the service ID will never change, it can be trusted to always match even if the service object and attributes change drastically.


Can a client make persistent changes to the attributes of a service?

A client can't change the attributes of a service directly. No methods that change attributes exist in the ServiceRegistrar interface. Such methods exist only in the ServiceRegistration interface, which is implemented by the object returned when service is registered. Thus, a client must go through the service to change to an attribute, and the service has the option of denying the request. Whether or not an attribute change is persistent across network failures is also the responsibility of the service itself.

If a service wishes to be administratable, its service object should implement the net.jini.admin.Administratable interface. This interface defines just one method, getAdmin(), which returns an object that should implement the net.jini.admin.JoinAdmin interface, as well as other service-specific admin interfaces. If a service doesn't want anyone besides itself to change an attribute, the Entry class for that attribute should implement the net.jini.lookup.entry.ServiceControlled interface.


To what extent is Jini dependent upon IP?

The current implementation of Jini is IP based, though other protocols could potientially be supported in the future. Such support for other protocols may involve gateways to IP.

Currently, a device that wishes to participate in a Jini federation must somehow get an IP address. The device must in fact already have an IP address before it sends the presence announcement packet (multicast request protocol). The lookup service extracts the IP address from the presence announcement packet in order connect back to the device to complete the discovery process via the unicast discovery protocol.

The Jini specifications themselves are silent about the process by which devices will get IP addresses. In particular, the lookup service has no involvement in the process of assigning IP addresses. It is likely that IP addresses will be dynamically assigned by a DHCP server or some other automatic mechanism when a device goes on-line.

Other than the discovery protocols, the Jini specification is quite independent of IP. Once a lookup service has been found, everything is RMI, and Jini is shielded from protocol details. Programmers who use the classes in the Jini API that support discovery, such as JoinManager and LookupDiscovery, will find that the IP dependency is well hidden from their code. In addition, the APIs that support leasing, distributed events, and distributed transactions are independent of IP.


How can I control the lease length granted by a lookup service when I register my service?

When you register a service either via the ServiceRegistrar or the JoinManager, you can specify a desired lease duration. The lookup service may grant a lease whose duration is shorter (but not longer) than the requested duration. In practice, a lookup service likely has a maximum lease length that it observes when granting leases to registering services. You can manage the maximum lease duration offered by a lookup service, if you have permission, via the admin interface to the lookup service itself. For the details, see the following text, which is based heavily on a post written by Brian Murphy:

If you look at the code in RegistrarImpl.java, you will see

    private long minMaxServiceLease = 1000 * 60 * 5;
private long minMaxEventLease   = 1000 * 60 * 30;

These values indicate that, by default, the maximum length of a service lease is 5 minutes; and the maximum length of a lease on event notification is 30 minutes. When a service requests a lease duration of Long.MAX_VALUE (either in the service itself or through the JoinManager), the lookup service interprets such a request to mean: "assign a lease duration that is no greater than the default maximum lease duration". Thus, if your service requests a lease duration of Long.MAX_VALUE, then lookup will usually assign a duration that is 5 minutes (or 30 minutes for event notifications); but might assign a smaller duration. The Lookup Specification addresses this issue.

If you want to assign longer lease durations, you can change the default maximum values through the RegistrarAdmin interface. This is something that the administrator of the lookup would typically do based on the needs of the various services that interact with the administrator's lookup.

To do this, you would get a reference to the RegistrarAdmin through the Registrar itself. For example,

ServiceRegistrar proxy = (CreateLookup.create(...)).reg;
RegistrarAdmin adminProxy
= (RegistrarAdmin)(((Administrable)proxy).getAdmin());

adminProxy.setMinMaxServiceLease(1000*60*25);
adminProxy.setMinMaxEventLease(1000*60*90);

Now, when you ask for a lease duration of Long.MAX_VALUE, 25 minutes or less will be granted for services; and 90 minutes or less will be granted for event notifications.

Note, that lookup services will not typically grant services not having the appropriate privledges the ability to change the lookup's configurable items. Usually the lookup service admin will have a GUI (possibily even a GUI registered as a service in the lookup itself) that is password protected; and which allows the administrator - and no one else - to change such items.

Because, in your test environment, you are both the creator/administrator of the lookup service and the creator of the service, you have the ability to change these items from your program.

One final note with respect to lease durations. At the top of RegistrarImpl.java, you will see the constant

MAX_LEASE (= 1000L * 60 * 60 * 24 * 365 * 1000)

This is the largest value that you can request the lookup reset the default max lease duration to; anything greater and you will get an IllegalArgumentException.


How do I perform advanced searches during lookup?

An example of this problem is a client that needs to find a display service that is at least 640 by 480 pixels. Assume that the well-known interface for displays is called Display and that Display services usually register a Resolution attribute that contains a screen width and height in pixels. You could look for a Display service that has a resolution of 640 by 480, but how could you find a Display that has at least 640 by 480 resolution?

Although the lookup service matching semantics only support exact matching, you could first get an array of all the different resolutions supported by currently registered Display services by using the ServiceRegistrar.getFieldValues() method. Once you know the range of available resolutions, you could set the attributeSetTemplates field of the ServiceTemplate to perform exact match lookups for the resolutions you are interested in.


What is the difference between Jini and CORBA?

CORBA is perhaps more akin to RMI than Jini, but CORBA includes a service called the trader service that is somewhat reminiscent of the Jini lookup service. CORBA, which stands for Common Object Request Broker Architecture, enables you to invoke methods on remote objects written in any programming language. RMI, which stands for Remote Method Invocation, enables you to invoke methods on Java objects in remote virtual machines. The objects needn't have been written in the Java programming language, but they do need to be running in a Java virtual machine. Thus, they most likely were written in some language that was compiled to Java class files, and by far the most common language compiled to Java class files is Java.

CORBA has a naming service that lets you look up a remote object by name and obtain a remote reference to it. RMI has a registry server that let you do the same thing: look up a remote object by name and obtain a remote reference to it. CORBA departs from RMI, however, in that to use the remote reference by invoking methods on a local stub, CORBA requires that the client have the definition of the stub locally. (In other words, CORBA requires that the code for the stub object be known to the developers that create the client.) RMI, by contrast, can send the class files for a stub object across the wire. Because an RMI client can dynamically load the code for a stub object, that code need not be known to the developers of the client.)

CORBA does offer a "dynamic invocation interface" that enables clients to use remote objects without the stub definition, but it is more complex to use than just invoking methods on a local stub. The difference in complexity is similar to the difference between using a Java object through its interface and using the same Java object via the reflection API.

Another difference between CORBA and RMI is that RMI lets you pass objects by value as well as by reference when you invoke a remote method. Up until the CORBA/IIOP 2.2 specification was released in 1998, CORBA only allowed you to pass objects by reference. The 2.2 specification added support for objects by value, but this functionality yet may not be supported in many CORBA implementations.

A significant difference between CORBA and RMI is that when a subclass object is passed to a remote method by value, CORBA will truncate the object to the type declared in the method parameter list. For example, if a CORBA remote method expects an Animal and the client passes a Dog (a subclass of Animal), the remote object will receive an Animal (a truncated Dog), not a Dog. Because RMI can send the class files for the Dog across the network, the RMI remote object will receive a Dog. If the remote virtual machine has no idea what a Dog is, it will pull the class file for Dog down across the network.

As mentioned previously, CORBA does include one service that is reminescent of Jini's lookup service: the CORBA trader service. Instead of just supplying a name with which a remote object is associated, as you do with the CORBA naming service (or the RMI registry), you describe the type of remote object you are seeking. Similarly, you can look up a Jini service by type. The Jini lookup service offers a bit more flexibility in searching, however, because you can also search by a globally unique service ID and by attributes. But the most important difference between the CORBA trader service and the Jini lookup service lies in what they return as a result of the query. The CORBA trader service returns a remote reference to a matching remote object. The Jini lookup service returns a proxy object by value.

Thus, when you get a remote reference back from the CORBA trader service (assuming you have the stub definition), you can talk to the remote object by invoking methods on the local stub. The local stub will talk across the network to the remote object via CORBA. When you talk to a Jini service object, on the other hand, that service object may not talk across the network at all. It may implement the service in its entirety locally in the client's virtual machine. Or, it may talk across the network to a server, servers, or some hardware via sockets and streams. Or, the service object may actually be an RMI stub that communicates across the network to a remote RMI object via the RMI wire protocol. The service object returned by Jini can use any network protocol to communicate across the network. It could even use CORBA.


Should Jini service interfaces extend Remote?

When you design an object whose methods you want to invoke from a different virtual machine via RMI, you must design an interface through which the client interacts with your object. Your object -- called a remote object -- should extend some subclass of java.rmi.server.RemoteObject, such as UnicastRemoteObject or Activatable. Each interface through which clients will interact with your remote object should extend the tag interface java.rmi.Remote. The Remote interface identifies interfaces whose methods may be invoked from non-local virtual machines. Each method in an interface that extends Remote should declare java.rmi.RemoteException in its throws clause. The checked RemoteException indicates that some problem occurred in fulfilling the remote method invocation request.

When you design a Jini service interface, you define the way in which clients will talk to your Jini service. Clients will receive some implementation of your interface from the lookup service. This object will likely be passed as a parameter or return value of an RMI remote method invocation between the client and the lookup service.

In general, Jini service interfaces should not extend java.rmi.Remote, because that would imply that the service is implemented as an RMI remote object. It is more flexible to allow specific implementations of the service to bring about the Remote interface themselves if they are to be an RMI remote object. By not incorporating Remote in the service interface, you give people who provide implementations of the service the *option* of being an RMI remote object.

The methods of the service interface should, on the other hand, declare java.rmi.RemoteException in their throws clause. Any method that hopes ever to be invoked via RMI must declare java.rmi.RemoteException. Thus, to give providers of implementations of your service interface the option of being an RMI remote object, you must declare RemoteException in each method declared in the service interface.

Adding RemoteException to the throws clauses of the methods of your Jini service interface indicates not only that RMI may be used by implementations, but that the network in general may be used by implementations. Thus, if an implementation of your Jini service uses sockets and streams to talk across the network to a server, it should indicate network problems by throwing some subclass of RemoteException. Likewise, if an implementation uses CORBA or DCOM to talk across the network to remote objects, it should throw some subclass of RemoteException to indicate network problems.


Why does an application that exports an RMI remote object need to be able to load the stub class?

A stub class is generated by rmic from the class file that defines a class for a remote object. The stub class implements all the same remote interfaces as the remote object's class. When a client holds a remote reference to a remote object, it is actually holding a local reference to a local instance of the stub class for that remote object. Because the stub class implements all the same remote interfaces as the remote object's class, the client can invoke any method on the stub through the remote interfaces that it could invoke on the remote object.

Since the client must instantiate a stub object, it makes sense that the client needs to be able to load the class file for the stub class. The reason the server must also be able to load the stub class is less obvious. A stub class can be distributed along with clients, which enables the client to load the stub class from a local repository, such as from its local class path. However, RMI offers an alternative that makes it unnecessary to distribute stub classes with clients.

In an RMI method invocation, objects can be passed as parameters, returned as return values, or thrown as exceptions, either by value or by reference. If an object is a remote object, it is passed by reference; otherwise, it is passed by value.

To pass an object by reference, the remote object itself is replaced at serialization time by its stub. In other words, to pass a remote object by reference, RMI passes its stub by value. Like any other serialized object RMI passes along the wire, it optionally annotates the serialized stream with a codebase URL. If a recipient of a serialized stub (an RMI client) doesn't have the class file for the stub class available locally, the recipient can go to the codebase URL to download the class file across the network. By enabling the mobility of stub classes across the network, RMI eliminates the necessity to distribute stub classes with clients.

To pass an object by value, the state of the object is serialized, and the serialized stream is optionally annotated with a codebase URL. The codebase specifies how the recipient of the serialized object can get hold of any class files necessary for deserialization that aren't available at the receiving end.

Now, back to the original question: Why does the server that exports a remote object need to have the stub available? When a server exports a remote object for use by a client, the server needs both the remote object class itself and the stub class, because in the process of exporting a remote object, an instance of the stub is created in the local (server's) virtual machine. In the process of exporting a remote object, the stub class is requested of the class loader that loaded the remote object's class, so the class must be available locally to that particular class loader. Whenever a client requests a remote reference to the remote object via the rmi registry naming server, the client is sent the serialized stub object. Thus, even though the server application typically doesn't use the stub class overtly, it's needed by RMI's serialization machinery when the remote object is exported.


How should I partition classes at the RMI codebase among jar and class files?

The two potentially contradictory goals you should aim for when thinking about how to partition the classes you need to make available through the RMI codebase are minimizing download time for needed classes and minimizing downloading of unneeded classes.

If you place only individual class files at the codebase, then clients won't have to download any class files they don't require. They will, instead, grab each class file they need individually. This approach eliminates the downloading of unneeded classes, however, it may not yield the minimum possible download time for needed classes.

When you place only individual class files at the codebase, clients must make a separate HTTP request for each class file. Were you to place all your class files in a single JAR file, only one HTTP request would be needed to grab the JAR file, which contains all the class files. This approach eliminates the time required by all those HTTP requests for individual class files, but forces all clients to download all class files that come in the JAR package, even if they only need one of those class files.

Nevertheless, depending on how big the JAR file is and how many classes contained in the JAR file are actually needed by a particular client, it is often more efficient to place the class files in a JAR. Not only does the client save time by only having to make one HTTP request, the contents of the JAR file can be compressed. (A JAR file, after all, is a ZIP file.)

Of course, if your JAR file contains many class files that may not be needed by many clients, it may still be more efficient to offer individual class files. An alternative, in-between approach that you can also consider taking when you've got many class files that many clients won't need is to distribute the class files among several JAR files. If you take this approach, you'll need to put a Class-Path: attribute in the manifest file of the initial JAR file that points to the other JAR files. You can place the classes that most clients will need in the initial JAR file, and classes that will be required less frequently in the other JAR files.

For more information, check out John McClain's presentation on "How to avoid Codebase Problems":

http://developer.jini.org:80/exchange/users/jmcclain/index.html


How do I use entry beans in my Jini service attributes?

To help users view and edit the attributes attached to your Jini service, you can create entry beans for them. An entry bean is a class that follows the JavaBeans naming conventions, which serves as an adapter between a user and a service attribute entry. To view and manipulate the attribute entry, the user interacts with the entry bean.

To be a JavaBean, you need only declare a no-arg constructor and implement Serializable. Nevertheless, most beans go further than that by declaring get and set methods for properties, addListener and removeListener methods for events, and potentially providing other support classes such as BeanInfos, PropertyEditors, and Customizers.

An entry bean is any JavaBean that implements the EntryBean interface:

package net.jini.lookup.entry.EntryBean;

public interface EntryBean {
    public void makeLink(Entry e);
    public Entry followLink();
}

To connect an entry bean to its entry, you pass a reference to the entry to makeLink(). followLink() returns a reference to the Entry passed to makeLink().

You must give to each entry bean class a name consisting of the name of the entry plus "Bean." For example, an entry bean for a "Provider" attribute entry would have to be named: "ProviderBean".

To enable the bean to be found and loaded, you merely make the class files for the bean (and any supporting class files, such as class files for Customizers, BeanInfos, etc.) available at the codebase that contains the class files for the attribute entry. You needn't register the bean as an attribute. When a tool goes looking for an entry bean to help a user interact with an entry, the tool will look in the codebase specified in the serialized image of the entry object.


How are lookups by type implemented?

Jini's lookup service enables clients to look for specific kinds of services. When multiple services of the desired kind exist, clients can use attributes to narrow their search and help them select the best service for their needs.

To specify the kind of service desired, clients specify Java types. The types specified are most often interfaces, but can also be classes. Because developers of Jini clients must indicate the kind of desired service with a Java type, the developer knows about the type at compile-time, and will therefore know how to user whatever object is returned by the lookup service.

To indicate a Java type when performing a lookup, clients must pass to the service registrar's lookup() method an array of references to Class instances that represent the desired types in the client's virtual machine. Any registered service whose service object is an instance of each type specified by the client matches the lookup. When the lookup service looks through its set of registered services, however, it merely compares the type names of the types represented by the client's specified Class instances with the types names of the registered service objects. It doesn't compare any class information.

Because the lookup service compares types by name only, two different types with the same fully qualified name would match. Nevertheless, when the service object for such a mismatched type gets back to the client, however, the deserialization process would detect the mismatch and throw an exception.

The reason the lookup service can get by with performing merely a string compare on the type names is that:

  1. Java types names are intimately associated with an interface and a semantic contract that objects of that name are supposed to fulfill. So a Java type name has more meaning than an arbitrarily assigned logical name.
  2. Java objects come with a global naming scheme that's supposed to make all fully qualified names unique. IBM, for example, is responsible for making sure no two types in the com.ibm namespace have the same fully qualified name, and they aren't supposed to let the world ever see anything they made whose name doesn't start with "com.ibm".
  3. Java has a bunch of rules of binary compatibility that enable each named type to evolve without breaking pre-existing code that uses the earlier versions of the named type.


Is there a way to receive notification when new services register with a lookup service?

Yes. The ServiceRegistrar interface includes a notify() method:

public EventRegistration notify(ServiceTemplate tmpl,
    int transitions, RemoteEventListener listener,
    MarshalledObject handback, long leaseDuration)
    throws RemoteException;

You invoke notify() to register yourself (or some other listener) as interested in receiving a distributed event whenever the services that match the passed ServiceTemplate undergo a state change described by the transitions parameter.

The transitions parameter is a bitwise OR of any non-empty set of these three values, which are defined as constants in ServiceRegistrar:

TRANSITION_MATCH_MATCH
TRANSITION_MATCH_NOMATCH
TRANSITION_NOMATCH_MATCH

You build the ServiceTemplate for notify() in the same way you build it for lookup(). You can indicate explicit types, a service ID, attributes, which must exactly match, or wildcards in any of those fields, which match anything. The transitions are based on a change (or non-change) in the status of what matches your ServiceTemplate before and after any operation performed by anyone on the lookup service.

For example, TRANSITION_MATCH_MATCH indicates that at least one service item matched your template before and after an operation. TRANSITION_MATCH_NOMATCH indicates that, although at least one particular service item matched your template before an operation, it no longer matched your template after the operation.

To receive notification when new services are added to a lookup service, therefore, you simply specify a template that matches any service, and pass TRANSITION_NOMATCH_MATCH as the transition to the notify() method.


Does the discovery protocol limit Jini within a single subnet?

The discovery protocol is really three protocols in one:

  1. a multicast request protocol
  2. a multicast announcement protocol
  3. a unicast discovery protocol

When a service provider or client finds itself connected to a new and unfamiliar network, it sends out a presence announcement on a well-known multicast port. This is the multicast request protocol. Lookup services monitor this well-known port. When a lookup service receives a presence announcement, it inspects the packet and decides whether or not to contact the sender. If it decides to make contact, it establishes a direct unicast connection to a host and port included in the presence announcement. The service provider or client sends a ping across this direct connection, and the lookup service responds with a service registrar object. The ping/service registrar conversation is the unicast discovery protocol.

Lookup services may also periodically send a presence announcement to a well-known multicast port, which clients and service providers can monitor. This is the multicast announcement protocol. If a client or service provider receives such a presence announcement, they can make a direct unicast connection back to a host and port number included in the presence announcement. The two parties perform the unicast discovery protocol across this connection: the client or service provider sends a ping, and the lookup service sends a service registrar object.

The unicast discovery protocol can also be used when a client or service provider has a long-term relationship with a lookup service. A client or service provider can simply make a direct unicast connection to a lookup service, and exchange a ping for a service registrar object.

None of these three discovery sub-protocols is necessarily limited to a single subnet. The unicast discovery protocol, because it involves a known host and port where the lookup service resides, could be used across the internet. The other two protocol, because they involve multicast, will be more geographically limited. Nevertheless, whether or not a multicast packet reaches beyond the borders of the subnet in which it is launched depends on how the local system administrators set up the nearby gateways. A multicast packet may be limited to a single subnet, or it may migrate to multiple nearby subnets.


How are service IDs generated such that they can be globally unique?

The first time a Jini service registers itself with a lookup service, the lookup service creates a service ID for that service. The service provider is supposed to remember this ID forever. Every time it registers its service with any lookup service from that point forward, it should specify its service ID.

The service ID provided by the lookup service is supposed to be globally unique. In other words, a particular service ID, if it is ever generated, should be generated only once by any lookup service, anywhere in the universe, at any time. How does this work?

First of all, the service ID is 128 bits long. The size of the ID itself makes it unlikely that any two randomly generated service IDs would come out to be the same value, so long as the random number generators started with different seed values.

The Jini lookup service uses a technique that includes randomization, but also includes other techniques that in effect guarantees the uniqueness of each service ID until the year 3400. In 60 of the 128 bits, the lookup service expresses the current system time in the number of 100 nanosecond ticks since 1582. The rest of the ID is a random number and, in some lookup service implementations, a unique host address for the lookup service.


What are the ServiceRegistrar's browsing methods for, and how are they used?

The ServiceRegistrar has three methods that are called "browsing methods," getServiceTypes(), getEntryClasses(), and getFieldValues(). These three methods are called "browsing methods" because their intended purpose is to enable clients to browse the services and attributes in the lookup service.

The getServiceTypes() method takes a ServiceTemplate (the same ServiceTemplate that's passed to the lookup() methods) and a String prefix. The method returns an array of Class instances representing the most specific types (classes or interfaces) of the service objects that match the template which are neither equal to, nor a superclass of, any of the types specified in the template and that have names that start with the specified prefix. The service object or objects for whom Class instances are returned are all instances of all the types (if any) passed in the template, but the Class instances returned are all more specific than (are subclasses or subinterfaces of) the types specified in the template. Each class appears only once in the returned array, and the order of the classes in the returned array is arbitrary.

The getEntryTypes() method takes a ServiceTemplate, and returns an array of Class instances that represent the most specific classes of entries for those service items that match the template which either don't match any entry template or are a subclass of an entry template. Each class appears only once in the returned array, and the order of the classes in the returned array is arbitrary.

The getFieldValues() method takes a ServiceTemplate, an integer index, and a String field name. The method returns an array of Objects for the named field of all instances of the entry that appears in the ServiceTemplate's Entry[] array at the passed index in any matching service item. Each object of a particular class and value appears only once in the returned array, and the order of the Object values in the returned array is arbitrary.

The behavior and purpose of these methods can be obscure. A good way to think of them is enabling clients to sequentially narrow queries of the lookup service. A client, such as a graphical lookup service browser, could begin by invoking getServiceTypes() with an empty template. The getServiceTypes() method returns all possible service types registered in the lookup service, which the browser could display. The user could select one or more type, then push the Requery button. The browser would add that type to the service template, and invoke getServiceTypes() again. A smaller list of types would be returned, and the browser would display those. The user could select one and press a Entries button. The browser would form a template with the most recently selected service type or types, and invoke getEntryTypes(). The getEntryTypes() method would return an array of entry classes, which the browser could then display. The user could select some entries, and a field of a selected entry, and push a Fields button. The browser would build a template using the currently selected service and entry types, and pass the index of the entry class in which the user selected the field, and the name of the selected field to getFieldValues(). The browser would display all the values that getFieldValues() returned. The user could use these values to further narrow the search for a service. Eventually, the user could select and use a service.

Thus, these three "browsing methods" are geared towards helping clients, whether a human user is involved or not, to browse the lookup service. The arrays returned from the browsing methods can help the client further refine its queries, ultimately resulting in a ServiceTemplate that, when passed to lookup(), returns the most appropriate service object.


Why do I get com.sun.rmi.rmid.ExecOptionPermission exceptions when starting Jini?

A ExecOptionPermission exception, such as the one shown below, most likely means that you're having trouble with the new Java/RMID security system introduced in JDK1.3 and backported to JDK1.2.2.

java.rmi.activation.ActivateFailedException: failed to activate object; 
nested exception is:
          java.security.AccessControlException: access denied
(com.sun.rmi.rmid.ExecOptionPermission -Djava.security.policy=)

An explanation of the new security policy can be found here:

http://developer.java.sun.com/developer/products/jini/execpolicy.html

Starting RMID with the sun.rmi.activation.execPolicy property set to none will turn off security checks, and yield a "policy.all" like behavior:

rmid -J-Dsun.rmi.activation.execPolicy=none

Iain Shigeoka created a new ultra-promiscuous policy file, that will also turn off security checks in RMID. You can download this file as part of the jini-tools at:

http://sourceforge.net/projects/jini-tools




Google
  Web Artima.com   
Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use