Spec Index | A Collection of Jini Technology Helper Utilities and Services Specifications |
Version 2.0 |
LD - JiniTM Lookup Discovery Service
LD.1 Introduction
Part of the JiniTM Discovery and Join Specification is devoted to defining the discovery requirements for well-behaved Jini clients and services, called discovering entities, which are required to participate in the multicast discovery protocols. Discovering entities are required to send multicast discovery requests to lookup services with which the entities wish to interact. In addition, they must continuously listen for and act on announcements from the desired lookup services. Interactions with a discovered lookup service may involve registration with that lookup service, or may simply involve querying the lookup service for services of interest (or both). To find specific lookup services, discovering entities also need to be able to participate in the unicast discovery protocol.
Under certain circumstances, a discovering entity may find it useful to allow a third party to perform the entity's discovery duties. For example, an activatable entity that wishes to deactivate may wish to employ a special Jini technology-enabled service (Jini service)--referred to as a lookup discovery service--to perform discovery duties on its behalf. Such an entity may wish to deactivate for various reasons, one being to conserve computational resources. While the entity is inactive, the lookup discovery service, running on the same or a separate host, would employ the discovery protocols to find lookup services in which the entity has expressed interest and would notify the entity when a previously unavailable lookup service has become available.
The facilities of the lookup discovery service are of particular value in a scenario in which a new lookup service is added to a long-lived djinn containing multiple inactive services. Without the use of a lookup discovery service, the time frame over which the new lookup service is fully populated can be both unpredictable and unbounded.
To understand why this time frame can be unpredictable, consider the fact that an inactive service has no way of discovering a new lookup service. This means that each inactive service in the djinn that wishes to discover and join a new lookup service must first activate. Since activation of a service occurs when some client attempts to use the service, the amount of time that passes between the arrival of the new lookup service and the activation of the service can vary greatly over the range of services in the djinn. Thus, the time frame over which the lookup service becomes fully populated cannot be predicted because it could take arbitrarily long before all of the services activate and then discover and join the new lookup service.
In addition to being unpredictable, the time it takes for the lookup service to fully populate can also be unbounded. This is because there is no guarantee that the lookup service will send multicast announcements between the time the service activates and the time it deactivates. If the timing is right, it is possible that one or more of the services in the djinn may never discover and join the new lookup service. Thus, without the use of the lookup discovery service, the new lookup service may never fully populate.
As another example of a discovering entity that may find it useful to allow a third party to perform the entity's discovery duties, consider an entity that exists in an environment with one of the following characteristics:
- The environment does not support multicast.
- The environment contains no lookup services within the entity's multicast radius (roughly, the number of hops beyond which neither the multicast requests from the entity nor the multicast announcements from the lookup service will propagate).
- The environment does contain lookup service(s) within the entity's multicast radius, but at least one service needed by the entity is not registered with any lookup service within that radius.
If such an entity was provided with references to lookup services--located outside of the entity's multicast radius--that contain services needed by the entity, the entity could contact each lookup service and retrieve the desired service references. One way to provide the entity with access to those lookup services might be to configure the entity to find and use a lookup discovery service, operating beyond the entity's range, that can employ multicast discovery to find nearby lookup services belonging to groups in which the entity has expressed interest. After acquiring references to the targeted lookup services, the lookup discovery service would pass those references to the entity, providing the entity with access to the services registered with each lookup service. In this way, the entity participates in the multicast discovery protocols through a proxy relationship with the lookup discovery service, gaining access not only to lookup services outside of its own range, but also to all of the services registered with those lookup services.
Note that the scenario just described does not come without restrictions. For the lookup discovery service to be able to "link" an entity with lookup services in the way just described, the lookup discovery service must be registered with a lookup service having a location that either is known to the entity or is within the multicast radius of the entity. Furthermore, the lookup discovery service must be running on a host that is located within the multicast radius of the lookup services with which the entity wishes to be linked. That is, the entity must be able to find the lookup discovery service, and the lookup discovery service must be able to find the other desired lookup services.
To address these scenarios, the lookup discovery service participates in both the multicast discovery protocols and the unicast discovery protocol on behalf of a registered discovering entity or client. This service will listen for and process multicast announcement packets from Jini lookup services and will, until successful, repeatedly attempt to discover specific lookup services that the client is interested in finding.
Upon discovery of a previously undiscovered lookup service of interest, the lookup discovery service notifies all entities that have requested the discovery of that lookup service that such an event has occurred. The event mechanism employed by the lookup discovery service satisfies the requirements defined in the Jini Distributed Events Specification. Note that the entity that receives such an event notification does not have to be the client of the lookup discovery service; it may be a third-party event-handling service such as an event mailbox service. Once a client is notified of the discovery of a lookup service, it is left to the client to define the semantics of how it interacts with that lookup service. For example, the client may wish to join the lookup service, simply query it for other useful services, or both.
The lookup discovery service must be implemented as a well-behaved Jini service and must comply with all of the policies embodied in the Jini technology programming model. Thus, the resources granted by this service are leased, and implementations of this service must adhere to the distributed leasing model for Jini technology as defined in the Jini Distributed Leasing Specification. That is, the lookup discovery service will grant its services for only a limited period of time without an active expression of continuing interest on the part of the client.
LD.1.1 Goals and Requirements
The requirements of the interfaces and classes specified in this document are:
- To define a service that not only employs the Jini discovery protocols to discover, by way of either group association or
LookupLocator
association, lookup services in which clients have registered interest, but that also notifies its clients of the discovery of those lookup services
- To provide this service in such a way that it can be used by entities that deactivate
- To comply with the policies of the Jini technology programming model
The goals of this document are as follows:
- To describe the lookup discovery service
- To provide guidance in the use and deployment of services that implement the
LookupDiscoveryService
interface and related classes and interfacesLD.1.2 Other Types
The types defined in the specification of the
LookupDiscoveryService
interface are in thenet.jini.discovery
package. The following object types may be referenced in this chapter. Whenever referenced, these object types will be referenced in unqualified form:net.jini.core.discovery.LookupLocator net.jini.core.event.EventRegistration net.jini.core.event.RemoteEventListener net.jini.core.event.UnknownEventException net.jini.core.lease.Lease net.jini.core.lookup.ServiceID net.jini.core.lookup.ServiceRegistrar net.jini.discovery.DiscoveryEvent net.jini.discovery.DiscoveryGroupManagement net.jini.discovery.DiscoveryListener java.io.IOException java.rmi.MarshalledObject java.rmi.NoSuchObjectException java.rmi.RemoteException java.util.MapLD.2 The Interface
The
LookupDiscoveryService
interface defines the service--referred to as the lookup discovery service--previously introduced in this specification. Through this interface, other Jini services and clients may request that discovery processing be performed on their behalf. This interface belongs to thenet.jini.discovery
package, and any service implementing this interface must comply with the definition of a Jini service. This interface is not a remote interface; each implementation of this service exports a front end proxy object that implements this interface local to the client, using an implementation-specific protocol to communicate with the actual remote server (the back end). All of the proxy methods must obey normal Java Remote Method Invocation (RMI) remote interface semantics except where explicitly noted. Two proxy objects are equal (using theequals
method) if they are proxies for the same lookup discovery service.The one method defined in this interface throws a
RemoteException
,
and requires only the default serialization semantics so that this interface can be implemented directly using Java RMI.package net.jini.discovery; public interface LookupDiscoveryService { public LookupDiscoveryRegistration register( String[] groups, LookupLocator[] locators, RemoteEventListener listener, MarshalledObject handback, long leaseDuration) throws RemoteException; }When requesting a registration with the lookup discovery service, the client indicates the lookup services it is interested in discovering by submitting two sets of objects. Each set may contain zero or more elements. One set consists of the names of the groups whose members are lookup services the client wishes to be discovered. The other set consists of
LookupLocator
objects, each corresponding to a specific lookup service the client wishes to be discovered.For each successful registration the lookup discovery service will manage both the set of group names and the set of locators submitted. These sets will be referred to as the managed set of groups and the managed set of locators, respectively. The managed set of groups associated with a particular registration contains the names of the groups whose members consist of lookup services that the client wishes to be discovered through multicast discovery. Similarly, the managed set of locators contains instances of
LookupLocator
, each corresponding to a specific lookup service that the client wishes to be discovered through unicast discovery. The references to the lookup services that have been discovered will be maintained in a set referred to as the managed set of lookup services (or managed set of registrars).Note that when the general term managed set is used, it should be clear from the context whether groups, locators, or registrars are being discussed. Furthermore, when the term group discovery or locator discovery is used, it should be taken to mean, respectively, the employment of either the multicast discovery protocols or the unicast discovery protocol to discover lookup services that correspond to members of the appropriate managed set.
Finally, with respect to any remote operation, two classes of exception are referenced in this document. The term indefinite exception refers to a class of exception where any such exception does not allow assertions to be made about the probability of success (or failure) of future attempts to perform the operation. A
RemoteException
caused by a transient communication failure is one such example of an exception that can be classified as an indefinite exception. As such, whenever an indefinite exception is encountered, retrying the operation at a later time may be advisable because the operation may succeed when retried.The other class of exception to note is identified by the term definite exception, which refers to a class of exception where any such exception is indicative of a permanent failure. That is, when an operation fails as a result of an exception that can be classified as a definite exception, that exception allows one to assert that any future attempts to perform the failed operation will also be met with failure. In many cases, a
SecurityException
can be interpreted as a definite exception. Thus, whenever an operation fails as a result of a definite exception, because it is a virtual certainty that failure will again result on all future attempts to perform the operation, it is generally not advisable to retry the operation.LD.3 The Semantics
To employ the lookup discovery service to perform discovery on its behalf, a client must first register with the lookup discovery service by invoking the
register
method defined in theLookupDiscoveryService
interface. Theregister
method is the only method specified by this interface.LD.3.1 Registration Semantics
An invocation of the
register
method produces an object--referred to as aregistration object
(or simply aregistration
)--that is mutable. That is, the registration object contains methods through which it may be changed. Because registrations are mutable, each invocation of theregister
method produces a new registration object. Thus, theregister
method is not idempotent.The
register
method may throw aRemoteException
. Typically, this exception occurs when there is a communication failure between the client and the lookup discovery service. When this exception does occur, the registration may or may not have been successful.Each registration with the lookup discovery service is persistent across restarts (or crashes) of the lookup discovery service until the lease on the registration expires or is cancelled.
The
register
method takes the following as arguments:
- A
String
array, none of whose elements may benull
, consisting of zero or more elements in which each element is the name of a group whose members are lookup services that the client requesting the registration wishes to be discovered via group discovery
- An array of
LookupLocator
objects, none of whose elements may benull
, consisting of zero or more elements in which each element corresponds to a specific lookup service that the client requesting the registration wishes to be discovered via locator discovery
- A non-
null
RemoteEventListener
object which specifies the entity that will receive events notifying the registration when a lookup service of interest is discovered or discarded
- Either
null
or an instance ofMarshalledObject
specifying an object that will be included in the notification event that the lookup discovery service sends to the registered listener
- A
long
value representing the amount of time (in milliseconds) for which the resources of the lookup discovery service are being requestedThe
register
method returns an object that implements theLookupDiscoveryRegistration
interface. It is through this returned object that the client interacts with the lookup discovery service. This interaction includes activities such as group and locator management, state retrieval, and discarding discovered but unavailable lookup services so that they are eligible for rediscovery (see Section LD.4.1, "The LookupDiscoveryRegistration Interface" for definition of the semantics of the methods of theLookupDiscoveryRegistration
interface).The
groups
argument takes aString
array, none of whose elements may benull
. Although it is acceptable to specifynull
(which is equivalent toDiscoveryGroupManagement.ALL_GROUPS
) for thegroups
argument itself, if the argument contains one or morenull
elements, aNullPointerException
is thrown. If the value isnull
, the lookup discovery service will attempt to discover all lookup services located within the multicast radius of the host on which the lookup discovery service is running. If an empty array (equivalent toDiscoveryGroupManagement.NO_GROUPS
) is passed in, then no group discovery will be performed for the associated registration until the client, through the registration'ssetGroups
oraddGroups
method, changes the contents of the managed set of groups to either a non-empty set of group names ornull
.The
locators
argument takes an array ofLookupLocator
objects, none of whose elements may benull
. If either the empty array ornull
is passed in as thelocators
argument, then no locator discovery will be performed for the associated registration until the client, through the registration'saddLocators
orsetLocators
method, changes the managed set of locators to a non-empty set of locators. Although it is acceptable to inputnull
for thelocators
argument itself, if the argument contains one or more null elements, aNullPointerException
is thrown.If the
register
method is invoked with a set of group names and a set of locators in which either or both sets contain duplicate elements (where duplicate locators are determined byLookupLocator.equals
), the invocation is equivalent to constructing this class with no duplicates in either set.Upon discovery of a lookup service, through either group discovery or locator discovery, the lookup discovery service will send an event, referred to as a discovered event, to the listener associated with the registration produced by the call to
register
.After initial discovery of a lookup service, the lookup discovery service will continue to monitor the group membership state reflected in the multicast announcements from that lookup service. Depending on the lookup service's current group membership, the lookup discovery service may send either a discovered event or an event referred to as a discarded event. The conditions under which either a discovered event or a discarded event will be sent are as follows:
- If the multicast announcements from an already discovered lookup service indicate that the lookup service is a member of a new group, a discovered event will be sent to the listener of each registration that has yet to receive a discovered event for that lookup service, but that has previously registered interest in the new group.
- If the multicast announcements from an already discovered lookup service indicate that the lookup service has changed its group membership in such a way that the lookup service is no longer of interest to one or more of the registrations that previously registered interest in the groups of that lookup service, a discarded event will be sent to the listener of each such registration. This type of discarded event is sometimes referred to as a passive no-interest discarded event ("passive" because the lookup discovery service, rather than the client, initiated the discard process).
- If the multicast announcements from an already discovered lookup service are no longer being received, a discarded event will be sent to the listener of each registration that previously registered interest in one or more of that lookup service's member groups. This type of discarded event is sometimes referred to as a passive communication discarded event.
It is important to note that when the lookup discovery service (passively) discards a lookup service, due to group membership changes (lost interest) or unavailability (communication failure), the discarded event will be sent to only the listeners of those registrations that have previously requested that the affected lookup service be discovered through at least group discovery. That is, the listener of any registration that is interested in the affected lookup service through only locator discovery will not be sent either type of passive discarded event. This is because the semantics of the lookup discovery service assume that since the client, through the registration request, expressed no interest in discovering the lookup service through its group membership, the client must also have no interest in any group-related changes in that lookup service's state.
A more detailed discussion of the event semantics of the lookup discovery service is presented in Section LD.3.2, "Event Semantics".
A valid parameter must be passed as the
listener
argument of theregister
method. If anull
value is input to this argument, then aNullPointerException
will be thrown and the registration fails.Note that if an indefinite exception occurs while attempting to send a discovered or discarded event to a registration's listener, the lookup discovery service will continue to attempt to send the event until either the event is successfully delivered or the client's lease on that registration expires. If an
UnknownEventException
or a definite exception occurs while attempting to send a discovered or discarded event to a registration's listener, the lookup discovery service assumes that the client is in an unknown, possibly corrupt state, and will cancel the lease on the registration and clear the registration from its managed set.The state information maintained by the lookup discovery service includes the set of group names, locators, and listeners submitted by each client through each invocation of the
register
method, with duplicates eliminated. This state information contains no knowledge of the clients that register with the lookup discovery service. Thus, there is no requirement that a client identify itself during the registration process.LD.3.2 Event Semantics
For each registration created by the lookup discovery service, an event identifier will be generated that uniquely maps the registration to the listener as well as to the registration's managed set of groups and managed set of locators. This event identifier is returned as a part of the returned registration object and is unique across all other active registrations with the lookup discovery service.
Whenever the lookup discovery service finds a lookup service matching the discovery criteria of one or more of its registrations, it sends an instance of
RemoteDiscoveryEvent
(a subclass ofRemoteEvent
) to the listener corresponding to each such registration. The event sent to each listener will contain the appropriate event identifier.Once an event signaling the discovery (by group or locator) of a desired lookup service has been sent, no other discovered events for that lookup service will be sent to a registration's listener until the lookup service is discarded (either actively, by the client through the registration, or passively by the lookup discovery service) and then rediscovered. Note that more information about what it means for a lookup service to be discarded is presented in Section LD.3.1, "Registration Semantics" and the section of this specification titled "Discarding Lookup Services".
If, between the time a lookup service is discarded and the time it is rediscovered, a new registration is requested having parameters indicating interest in that lookup service, upon rediscovery of the lookup service an event will also be sent to that new registration's listener.
The sequence numbers for a given event identifier are strictly increasing (as defined in the Jini Distributed Events Specification), which means that when any two such successive events have sequence numbers that differ by only a value of 1, then no events have been missed. On the other hand, when the set of received events is viewed in order, if the difference between the sequence numbers of two successive events is greater than 1, then one or more events may or may not have been missed. For example, a difference greater than 1 could occur if the lookup discovery service crashes, even if no events are lost because of the crash. When two such successive events have sequence numbers whose difference is greater than 1, there is said to be a gap between the events.
When a gap occurs between events, the local state (on the client) related to the discovered lookup services may or may not fall out of sync with the corresponding remote state maintained by the lookup discovery service. For example, if the gap corresponds to a missed event representing the (initial) discovery of a targeted lookup service, the remote state will reflect this discovery, whereas the client's local state will not. To allow clients to identify and correct such a situation, each registration object provides a method that returns a set consisting of the proxies to the lookup services that have been discovered for that registration. With this information the client can update its local state.
When requesting a registration with the lookup discovery service, a client may also supply (as a parameter to the
register
method) a reference to an object, wrapped in aMarshalledObject
, referred to as a handback. When the lookup discovery service sends an event to a registration's listener, the event will also contain a reference to this handback object. The lookup discovery service will not change the handback object. That is, the handback object contained in the event sent by the lookup discovery service will be identical to the handback object registered by the client with the event mechanism.The semantics of the object input to the
handback
argument are left to each client to define, althoughnull
may be input to this argument. The role of thehandback
object in the remote event mechanism is detailed in the Jini Distributed Events Specification.LD.3.3 Leasing Semantics
When a client registers with the lookup discovery service, it is effectively requesting a lease on the resources provided by that service. The initial duration of the lease granted to a client by the lookup discovery service will be less than or equal to the requested duration reflected in the value input to the
leaseDuration
argument. That value must be positive,Lease.FOREVER
, orLease.ANY
. If any other value is input to this argument, anIllegalArgumentException
will be thrown. The client may obtain a reference to theLease
object granted by the lookup discovery service through the associated registration returned by the service (see Section LD.4.1, "The LookupDiscoveryRegistration Interface").LD.4 Supporting Interfaces and Classes
The lookup discovery service depends on the
LookupDiscoveryRegistration
interface, as well as on the concrete classesRemoteDiscoveryEvent
andLookupUnmarshalException
.LD.4.1 The
LookupDiscoveryRegistration
InterfaceWhen a client requests a registration with the lookup discovery service, an object that implements the
LookupDiscoveryRegistration
interface is returned. It is through this interface that the client manages the state of its registration with the lookup discovery service.package net.jini.discovery; public interface LookupDiscoveryRegistration { public EventRegistration getEventRegistration(); public Lease getLease(); public ServiceRegistrar[] getRegistrars() throws LookupUnmarshalException, RemoteException; public String[] getGroups() throws RemoteException; public LookupLocator[] getLocators() throws RemoteException; public void addGroups(String[] groups) throws RemoteException; public void setGroups(String[] groups) throws RemoteException; public void removeGroups(String[] groups) throws RemoteException; public void addLocators(LookupLocator[] locators) throws RemoteException; public void setLocators(LookupLocator[] locators) throws RemoteException; public void removeLocators(LookupLocator[] locators) throws RemoteException; public void discard(ServiceRegistrar registrar) throws RemoteException; }As with the
LookupDiscoveryService
interface, theLookupDiscoveryRegistration
interface is not a remote interface. Each implementation of the lookup discovery service exports proxy objects that implement this interface local to the client, using an implementation-specific protocol to communicate with the actual remote server. All of the proxy methods must obey normal Java RMI remote interface semantics except where explicitly noted. Two proxy objects are equal (using theequals
method) if they are proxies for the same registration created by the same lookup discovery service.The discovery facility of the lookup discovery service, together with its event mechanism, make up the set of resources clients register to use. Because the resources of the lookup discovery service are leased, access is granted for only a limited period of time unless there is an active expression of continuing interest on the part of the client.
When a client uses the registration process to request that a lookup discovery service perform discovery of a set of desired lookup services, the client is also registered with the service's event mechanism. Because of this implicit registration with the event mechanism, the lookup discovery service "bundles" both resources under a single lease. When that lease expires, both discovery processing and event notifications will cease with respect to the registration that resulted from the client's request.
To facilitate lease management and event handling, the
LookupDiscoveryRegistration
interface defines methods that allow the client to retrieve its event registration information. Additional methods defined by this interface allow the client to retrieve references to the registration's currently discovered lookup services, as well as to modify the managed sets of groups and locators.If the client's registration with the lookup discovery service has expired or been cancelled, then any invocation of a remote method defined in this interface will result in a
NoSuchObjectException
. That is, any method that communicates with the back-end server of the lookup discovery service will throw aNoSuchObjectException
if the registration on which the method is invoked no longer exists. Note that if a client receives aNoSuchObjectException
as a result of an invocation of such a method, although the client can assume that the registration no longer exists, the client cannot assume that the lookup discovery service itself no longer exists.Each remote method of this interface may throw a
RemoteException
. Typically, this exception occurs when there is a communication failure between the client and the lookup discovery service. Whenever this exception occurs as a result of the invocation of one of these methods, the method may or may not have completed its processing successfully.LD.4.1.1 The Semantics
The methods defined by this interface are organized into a set of accessor methods, a set of group mutator methods, a set of locator mutator methods, and the
discard
method. Through the accessor methods, various elements of a registration's state can be retrieved. The mutator methods provide a mechanism for changing the set of groups and locators to be discovered for the registration. Through thediscard
method, a particular lookup service may be made eligible for rediscovery.The
getEventRegistration
method returns anEventRegistration
object that encapsulates the information the client needs to identify a notification sent by the lookup discovery service to the registration's listener. This method is not remote and takes no arguments.The
getLease
method returns theLease
object that controls a client's registration with the lookup discovery service. It is through theLease
object returned by this method that the client requests the renewal or cancellation of the registration with the lookup discovery service. This method is not remote and takes no arguments.Note that the object returned by the
getEventRegistration
method also provides agetLease
method. That method and thegetLease
method defined by theLookupDiscoveryRegistration
interface both return the sameLease
object. ThegetLease
method defined here is provided as a convenience to avoid the indirection associated with thegetLease
method on theEventRegistration
object, as well as to avoid the overhead of making two method calls.The
getRegistrars
method returns a set of instances of theServiceRegistrar
interface. Each element in the set is a proxy to one of the lookup services that have already been discovered for the registration. Additionally, each element in the set will be unique with respect to all other elements in the set, as determined by theequals
method provided by each element. The contents of the set make up the current remote state of the set of lookup services discovered for the registration. This method returns a new array on each invocation.This method can be used to maintain synchronization between the set of discovered lookup services making up a registration's local state on the client and the registration's corresponding remote state maintained by the lookup discovery service. The local state can become unsynchronized with the remote state when a gap occurs in the events received by the registration's listener.
According to the event semantics of the lookup discovery service, if there is no gap between two sequence numbers, no events have been missed and the states remain synchronized with each other; if there is a gap, events may or may not have been missed. Therefore, upon finding gaps in the sequence of events, the client can invoke this method and use the returned information to synchronize the local state with the remote state.
To construct its return set, the
getRegistrars
method retrieves from the lookup discovery service the set of lookup service proxies making up the registration's current remote state. When the lookup discovery service sends the requested set of proxies, the set is sent as a set of marshalled instances of theServiceRegistrar
interface. The lookup discovery service individually marshals each proxy in the set that it sends because if it were not to do so, any deserialization failure on the set would result in anIOException
, and failure would be declared for the whole deserialization process, not just an individual element. This would mean that all elements of the set sent by the lookup discovery service--even those that were successfully deserialized--would be unavailable to the client. Individually marshalling each element in the set minimizes the "all or nothing" aspect of the deserialization process, allowing the client to recover those proxies that can be successfully unmarshalled and to proceed with processing that might not be possible otherwise.When constructing the return set, this method attempts to unmarshal each element of the set of marshalled proxy objects sent by the lookup discovery service. When failure occurs while attempting to unmarshal any of those elements, this method throws an exception of type
LookupUnmarshalException
(described later). It is through the contents of that exception that the client can recover any available proxies and perform error handling related to the unavailable proxies. The contents of theLookupUnmarshalException
provide the client with the following useful information:
- The knowledge that a problem has occurred while unmarshalling at least one of the elements making up the remote state of the registration's discovered lookup services
- The set of proxy objects that were successfully unmarshalled by the
getRegistrars
method
- The set of marshalled proxy objects that could not be unmarshalled by the
getRegistrars
method
- The set of exceptions corresponding to each failed attempt at unmarshalling
The type of exception that occurs when attempting to unmarshal an element of the set sent by the lookup discovery service is typically an
IOException
or aClassNotFoundException
(usually the more common of the two). AClassNotFoundException
occurs whenever a remote object on which the marshalled proxy depends cannot be retrieved and loaded, usually because the codebase of one of the object's classes or interfaces is currently "down." To address this situation, the client may wish to proceed with its processing using the successfully unmarshalled proxies, and attempt to unmarshal the unavailable proxies (or re-invoke this method) at some later time.If the
getRegistrars
method returns successfully without throwing aLookupUnmarshalException
, the client is guaranteed that all marshalled proxies belonging to the set sent by the lookup discovery service have each been successfully unmarshalled; the client then has a snapshot--relative to the point in time when this method is invoked--of the remote state of the lookup services discovered for the associated registration.The
getGroups
method returns an array consisting of the group names from the registration's managed set; that is, the names of the groups the lookup discovery service is currently configured to discover for the associated registration. If the managed set of groups is empty, this method returns the empty array. If there is no managed set of groups associated with the registration (that is, the lookup discovery service is configured to discoverDiscoveryGroupManagement.ALL_GROUPS
for the registration), thennull
is returned.The
getLocators
method returns an array consisting of theLookupLocator
objects from the registration's managed set; that is, the locators of the specific lookup services the lookup discovery service is currently configured to discover for the associated registration. If the managed set of locators is empty, this method returns the empty array.With respect to a particular registration, the groups to be discovered may be modified using the methods described in this section. In each case, a set of groups is represented as a
String
array, none of whose elements may benull
. If any set of groups input to one of these methods contains one or more null elements, aNullPointerException
is thrown. The empty set is denoted by the empty array (DiscoveryGroupManagement.NO_GROUPS
), and "no set" is indicated bynull
(DiscoveryGroupManagement.ALL_GROUPS
). No set indicates that all lookup services within the multicast radius should be discovered, regardless of group membership. Invoking any of these methods with an input set of groups that contains duplicate names is equivalent to performing the invocation with the duplicate group names removed from the input set.The
addGroups
method adds a set of group names to the registration's managed set. This method takes one argument: aString
array consisting of the set of group names with which to augment the registration's managed set.If the registration has no current managed set of groups to augment, this method throws an
UnsupportedOperationException
. If the parameter value isnull
, this method throws aNullPointerException
. If the parameter value is the empty array, then the registration's managed set of groups will not change.The
setGroups
method replaces all of the group names in the registration's managed set with names from a new set. This method takes one argument: aString
array consisting of the set of group names with which to replace the current names in the registration's managed set.If
null
is passed tosetGroups
, the lookup discovery service will attempt to discover any undiscovered lookup services located within range of the lookup discovery service, regardless of group membership.If the empty set is passed to
setGroups
, then group discovery will be halted until the registration's managed set of groups is changed--through a subsequent call to this method or toaddGroups
--to a set that is either a non-empty set of group names ornull
.The
removeGroups
method deletes a set of group names from the registration's managed set. This method takes one argument: aString
array containing the set of group names to remove from the registration's managed set.If the registration has no current managed set of groups from which to remove elements, this method throws an
UnsupportedOperationException
. Ifnull
is input, this method throws aNullPointerException
. If the registration does have a managed set of groups from which to remove elements, but either the input set is empty or none of the elements in the input set match any element in the managed set, then the registration's managed set of groups will not change.Once a new group name has been placed in the registration's managed set as a result of an invocation of either
addGroups
orsetGroups
, if there are lookup services belonging to that group that have already been discovered for that registration, no event will be sent to the registration's listener for those particular lookup services. However, attempts to discover any undiscovered lookup services belonging to that group will continue to be made on behalf of the registration.Any already discovered lookup service that is a member of one or more of the groups removed from the registration's managed set as a result of an invocation of either
setGroups
orremoveGroups
will be discarded and will no longer be eligible for discovery (for that registration), but only if that lookup service satisfies both of the following conditions:
- The lookup service is not a member of any group in the registration's new managed set resulting from the invocation of
setGroups
orremoveGroups
- With respect to the registration, the lookup service is not currently eligible for discovery through locator discovery; that is, the lookup service does not correspond to any element in the registration's managed set of locators.
With respect to a particular registration, the set of locators to discover may be modified using the methods described in this section. In each case, a set of locators is represented as an array of
LookupLocator
objects, none of whose elements may benull
. If any set of locators input to one of these methods contains one of more null elements, aNullPointerException
is thrown. Invoking any of these methods with a set of locators that contains duplicate locators (as determined byLookupLocator.equals
) is equivalent to performing the invocation with the duplicates removed from the input set.The
addLocators
method adds a set ofLookupLocator
objects to the registration's managed set. This method takes one argument: an array consisting of the set of locators with which to augment the registration's managed set.If
null
is passed toaddLocators
, aNullPointerException
will be thrown. If the parameter value is the empty array, the registration's managed set of locators will not change.The
setLocators
method replaces all of the locators in the registration's managed set withLookupLocator
objects from a new set. This method takes one argument: an array consisting of the set of locators with which to replace the current locators in the registration's managed set.If
null
is passed tosetLocators
, aNullPointerException
will be thrown.If the empty set is passed to
setLocators
, then locator discovery will be halted until the registration's managed set of locators is changed--through a subsequent call to this method or toaddLocators
--to a set that is non-null
and non-empty.The
removeLocators
method deletes a set ofLookupLocator
objects from the registration's managed set. This method takes one argument: an array containing the set ofLookupLocator
objects to remove from the registration's managed set.If
null
is passed toremoveLocators
, aNullPointerException
will be thrown. If any element of the set of locators to remove is not contained in the registration's managed set,removeLocators
takes no action with respect to that element. If the parameter value is the empty array, the managed set of locators will not change.Whenever a new locator is placed in the managed set as a result of an invocation of one of the locator mutator methods and that new locator equals none of the previously discovered locators (across all registrations), the lookup discovery service will attempt unicast discovery of the lookup service associated with the new locator.
If locator discovery is attempted for a registration, such discovery attempts will be repeated until one of the following events occurs:
- The lookup service is discovered
- The client's lease on the registration expires
- The client explicitly removes the locator from the registration's managed set
Upon discovery of the lookup service corresponding to the new locator, or upon finding a match between the new locator and a previously discovered lookup service, a discovered event will be sent to the registration's listener, unless that lookup service was previously discovered for that registration through group discovery.
Any already discovered lookup service corresponding to a locator that is removed from the registration's managed set as a result of an invocation of either
setLocators
orremoveLocators
will be discarded and will no longer be eligible for discovery, but only if it is not currently eligible for discovery through group discovery--that is, only if the lookup service is not also a member of one or more of the groups in the registration's managed set of groups.When the lookup discovery service removes an already discovered lookup service from a registration's managed set of lookup services, the lookup service is said to be discarded.
There are a number of situations in which the lookup discovery service will discard a lookup service:
- In response to a discard request resulting from an invocation of a registration's
discard
method
- In response to a declaration--via an invocation of one of the mutator methods on a registration--that there is no longer any interest in one or more of the registration's already discovered lookup services
- In response to the determination that the multicast announcements from an already discovered lookup service indicate that the lookup service has changed its group membership in such a way that the lookup service is no longer of interest to one or more of the registrations that previously registered interest in the groups of that lookup service
- In response to the determination that the multicast announcements from an already discovered lookup service are no longer being received
For each of these cases, whenever the lookup discovery service discards a lookup service, it will send an event to the registration's listener to notify it that the lookup service has been discarded.
The
discard
method provides a mechanism for registered clients to inform the lookup discovery service of the existence of an unavailable--or unreachable--lookup service, and to request that the lookup discovery service discard that lookup service and make it eligible for rediscovery.The
discard
method takes a single argument: the proxy to the lookup service to discard. This method takes no action if the parameter to this method equals none of the proxies reflected in the managed set (using proxy equality as defined in the Jini Lookup Service Specification. Ifnull
is passed todiscard
, aNullPointerException
is thrown.Although the lookup discovery service monitors the multicast announcements from all discovered lookup services for indications of unavailability, it should be noted that there are conditions under which the lookup discovery service will not discard such a lookup service, even when the lookup service is found to be unreachable. Whether or not the lookup discovery service discards such an unreachable lookup service is dependent on how each registration is configured for discovery with respect to that lookup service. If every registration that is configured to discover the unreachable lookup service is configured to discover it through locator discovery only, the lookup discovery service will not discard the lookup service. In other words, in order for the lookup discovery service to discard a lookup service it has determined is unreachable, at least one registration must be configured for discovery of at least one group in which that lookup service is a member.
Thus, whenever a client determines that a previously discovered lookup service has become unreachable, it should not rely on the lookup discovery service to discard the lookup service. Instead, the client should inform the lookup discovery service--through the invocation of the registration's
discard
method--that the previously discovered lookup service is no longer available and that attempts should be made to rediscover that lookup service for the registration. Typically, a client determines that a lookup service is unavailable when the client attempts to use the lookup service but receives an exception (indefinite or definite) as a result of the attempt.Note that the lookup discovery service may be acting on behalf of numerous clients that have access to the same lookup service. If that lookup service becomes unavailable, many of those clients may invoke
discard
between the time the lookup service becomes unavailable and the time it is rediscovered. Upon the first invocation ofdiscard
, the lookup discovery service will re-initiate discovery of the relevant lookup service for the registration of the client that made the invocation. For all other invocations made prior to rediscovery, the registrations through which the invocation is made are sent a discarded event, and added to the list of registrations that will be notified when rediscovery of the lookup service does occur. That is, upon rediscovery of the lookup service, only those registrations through which thediscard
method was invoked will be notified.Upon successful completion of the
discard
method, the proxy requested to be discarded is guaranteed to have been removed from the managed set of the registration through which the invocation was made. No such guarantee is made with respect to when the discarded event is sent to each such registration's listener. That is, the event notifying the listeners that the lookup service has been discarded may or may not be sent asynchronously.LD.4.2 The
RemoteDiscoveryEvent
ClassWhen the lookup discovery service discovers or discards a lookup service matching the criteria established through one of its registrations, the lookup discovery service sends an instance of the
RemoteDiscoveryEvent
class to theRemoteEventListener
implemented by the client and registered with the lookup discovery service.package net.jini.discovery; public class RemoteDiscoveryEvent extends RemoteEvent { public RemoteDiscoveryEvent(Object source, long eventID, long seqNum, MarshalledObject handback, boolean discarded, Map groups) throws IOException {...} public boolean isDiscarded() {...} public ServiceRegistrar[] getRegistrars() throws LookupUnmarshalException {...} public Map getGroups() {...} }The
RemoteDiscoveryEvent
class provides an encapsulation of event information that the lookup discovery service uses to notify a registration of the occurrence of an event involving one or moreServiceRegistrar
objects (lookup services) in which the registration has registered interest. The lookup discovery service passes an instance of this class to the registration's discovery listener when one of the following events occurs:
- Each lookup service referenced in the event has been discovered for the first time or rediscovered after having been discarded.
- Each lookup service referenced in the event has been either actively or passively discarded.
RemoteDiscoveryEvent
is a subclass ofRemoteEvent
, adding the following additional items of abstract state:
- A
boolean
indicating whether the lookup services referenced by the event have been discovered or discarded
- A set of marshalled instances of the
ServiceRegistrar
interface having the characteristic that when each element is unmarshalled, the result is a proxy to one of the discovered or discarded lookup services referenced by the event
- A
Map
instance in which the elements of the map's key set are the instances ofServiceID
that correspond to each lookup service reference returned in the event, and the map's value set contains the corresponding member groups of each lookup service referenceMethods are defined through which this additional state may be retrieved upon receipt of an instance of this class.
Clients need to know not only when a targeted lookup service has been discovered, but also when it has been discarded. The lookup discovery service uses an instance of
RemoteDiscoveryEvent
to notify a registration when either of these events occurs, as indicated by the value of theboolean
state variable. When the value of that variable istrue
, the event is referred to as a discarded event; whenfalse
, it is referred to as a discovered event.LD.4.2.1 The Semantics
The constructor of the
RemoteDiscoveryEvent
class takes the following parameters as input:
- A reference to the lookup discovery service that generated the event
- The event identifier that maps a particular registration to both its listener and its targeted groups and locators
- The sequence number of the event being constructed
- The client-defined handback (which may be
null
)
- A flag indicating whether the event being constructed is a discovered event or a discarded event
- A
Map
whose key set contains the proxies to newly discovered or discarded lookup service(s) the event is to reference, and whose value set contains the corresponding member groups of each lookup serviceIf the
groups
parameter is empty, the constructor will throw anIllegalArgumentException
. If null is input to thegroups
parameter, the constructor will throw aNullPointerException
. If none of the proxies referenced in thegroups
parameter can be successfully serialized, the constructor will throw anIOException
.The
isDiscarded
method returns aboolean
that indicates whether the event is a discovered event or a discarded event. If the event is a discovered event, then this method returnsfalse
. If the event is a discarded event,true
is returned.The
getRegistrars
method returns an array consisting of instances of theServiceRegistrar
interface. Each element in the returned set is a proxy to one of the newly discovered or discarded lookup services that caused aRemoteDiscoveryEvent
to be sent. Additionally, each element in the returned set will be unique with respect to all other elements in the set, as determined by the equals method provided by each element. This method does not make a remote call. With respect to multiple invocations of this method, each invocation will return a new array.When the lookup discovery service sends an instance of
RemoteDiscoveryEvent
to the listener of a client's registration, the set of lookup service proxies contained in the event consists of marshalled instances of theServiceRegistrar
interface. The lookup discovery service individually marshals each proxy associated with the event because if it were not to do so, any deserialization failure on the set would result in anIOException
, and failure would be declared for the whole deserialization process, not just an individual element. This would mean that all elements of the set sent in the event--even those that can be successfully deserialized--would be unavailable to the client through this method. Just as with thegetRegistrars
method defined by theLookupDiscoveryRegistration
interface, individually marshalling each element in the set minimizes the "all or nothing" aspect of the deserialization process, allowing the client to recover those proxies that can be successfully unmarshalled and to proceed with processing that might not be possible otherwise.When constructing the return set, this method attempts to unmarshal each element of the set of marshalled proxy objects contained in the event. When failure occurs while attempting to unmarshal any of the elements of that set, this method throws an exception of type
LookupUnmarshalException
. It is through the contents of this exception that the client can recover any available proxies and perform error handling with respect to the unavailable proxies.If the
getRegistrars
method returns successfully without throwing aLookupUnmarshalException
, the client is guaranteed that all marshalled proxies sent in the event have each been successfully unmarshalled during that particular invocation. Furthermore, after the first such successful invocation, no more unmarshalling attempts will be made (because such attempts are no longer necessary), and all future invocations of this method are guaranteed to return an array with contents identical to the contents of the array returned by the first successful invocation.Note that an array, rather than a single proxy, is returned by the
getRegistrars
method so that implementations of the lookup discovery service can choose to "batch" the information sent to a registration. With respect to discoveries, batching the information may be particularly useful when a client first registers with the lookup discovery service.Upon initial registration, multiple lookup services are typically found over a short period of time, providing the lookup discovery service with the opportunity to send all of the initially discovered lookup services in only one event. Afterward, as so-called "late joiner" lookup services are found sporadically, the lookup discovery service may send events referencing only one lookup service.
Note that the event sequence numbers, as defined earlier in Section LD.3.2, "Event Semantics", are strictly increasing, even when the information is batched.
The
getGroups
method returns aMap
in which the elements of the map's key set are the instances ofServiceID
that correspond to each lookup service for which the event was constructed and sent. Each element of the returned map's value set is aString
array containing the names of the member groups of the associated lookup service whoseServiceID
equals to the corresponding key. This method does not make a remote call. On each invocation of this method, the sameMap
object is returned; that is, a copy is not made.The
Map
returned by thegetGroups
method is keyed by theServiceID
of each lookup service in the event, rather than by the proxy of each lookup service to avoid the deserialization issues addressed by thegetRegistrars
method. Thus, client's wishing to retrieve the set of member groups corresponding to any element of the array returned by thegetRegistrars
method, must use theServiceID
of the desired element from that array as the key to the get method of theMap
returned by this method and then cast toString
[].LD.4.2.2 Serialized Forms
Class serialVersionUID
Serialized Fields RemoteDiscoveryEvent
-9171289945014585248L boolean discarded
ArrayList marshalledRegs
ServiceRegistrar[] regs
Map groups
LD.4.2.3 The
LookupUnmarshalException
ClassRecall that when unmarshalling an instance of
MarshalledObject
, one of the following checked exceptions is possible:
- An
IOException
, which can occur while deserializing the object from its internal representation
- A
ClassNotFoundException
, which can occur if, while deserializing the object from its internal representation, either the class file of the object cannot be found, or the class file of an interface or class referenced by the object being deserialized cannot be found. Typically, aClassNotFoundException
occurs when the codebase from which to retrieve the needed class file is not currently availableThe
LookupUnmarshalException
class provides a mechanism that clients of the lookup discovery service may use for efficient handling of the exceptions that may occur when unmarshalling elements of a set of marshalled instances of theServiceRegistrar
interface. When elements in such a set are unmarshalled, theLookupUnmarshalException
class may be used to collect and report pertinent information generated when failure occurs during the unmarshalling process.package net.jini.discovery; public class LookupUnmarshalException extends Exception { public LookupUnmarshalException (ServiceRegistrar[] registrars, MarshalledObject[] marshalledRegistrars, Throwable[] exceptions) {...} public LookupUnmarshalException (ServiceRegistrar[] registrars, MarshalledObject[] marshalledRegistrars, Throwable[] exceptions, String message) {...} public ServiceRegistrar[] getRegistrars() {...} public MarshalledObject[] getMarshalledRegistrars() {...} public Throwable[] getExceptions() {...} }The
LookupUnmarshalException
class is a subclass ofException
, adding the following additional items of abstract state:
- A set of
ServiceRegistrar
instances in which each element is the result of a successful unmarshalling attempt
- A set of marshalled instances of
ServiceRegistrar
in which each element is the result of an unsuccessful unmarshalling attempt
- A set of exceptions (
IOException
,ClassNotFoundException
, or some unchecked exception) in which each element corresponds to one of the unsuccessful unmarshalling attemptsWhen exceptional conditions occur while unmarshalling a set of marshalled instances of
ServiceRegistrar
, theLookupUnmarshalException
class can be used not only to indicate that an exceptional condition has occurred, but also to provide information that can be used to perform error handling activities such as:
- Determining if it is feasible to continue with processing
- Reporting errors
- Attempting recovery
- Performing debug activities
LD.4.2.4 The Semantics
The constructor of the
LookupUnmarshalException
class has two forms. The first form of the constructor takes the following parameters as input:
- An array containing the set of instances of
ServiceRegistrar
that were successfully unmarshalled
- An array containing the set of marshalled
ServiceRegistrar
instances that could not be unmarshalled
- An array containing the set of exceptions that occurred during the unmarshalling process
The second form of the constructor takes the same arguments as the first and one additional argument: a
String
describing the nature of the exception.Each element in the exceptions parameter should be an instance of
IOException
,ClassNotFoundException
, or some unchecked exception. Furthermore, there is a one-to-one correspondence between each element in the exceptions parameter and each element in themarshalledRegistrars
parameter. That is, the element of the exceptions parameter corresponding to index i should be an instance of the exception that occurred while attempting to unmarshal the element at index i of themarshalledRegistrars
parameter.If the number of elements in the exceptions parameter does not equal the number of elements in the
marshalledRegistrars
parameter, the constructor will throw anIllegalArgumentException
.The
getRegistrars
method is an accessor method that returns an array consisting of instances ofServiceRegistrar
, where each element of the array corresponds to a successfully unmarshalled object. Note that the same array is returned on each invocation of this method; that is, a copy is not made.The
getMarshalledRegistrars
method is an accessor method that returns an array consisting of instances ofMarshalledObject
, where each element of the array is a marshalled instance of theServiceRegistrar
interface and corresponds to an object that could not be successfully unmarshalled. Note that the same array is returned on each invocation of this method; that is, a copy is not made.The
getExceptions
method is an accessor method that returns an array consisting of instances of Throwable, where each element of the array corresponds to one of the exceptions that occurred during the unmarshalling process. Each element in the return set is an instance ofIOException
,ClassNotFoundException
, or some unchecked exception. Additionally, there should be a one-to-one correspondence between each element in the array returned by this method and the array returned by thegetMarshalledRegistrars
method. Note that the same array is returned on each invocation of this method; that is, a copy is not made.LD.4.2.5 Serialized Forms
Class serialVersionUID
Serialized Fields LookupUnmarshalException
2956893184719950537L ServiceRegistrar[] registars
MarshalledObject[] marshalledRegistrars
Throwable[] exceptionsLD.5 History
Version Description v1.0 Initial release of this specification v2.0 Defined indefinite and definite exceptions, and removed references to bad object and bad invocation exceptions.
Miscellaneous corrections.
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
Spec Index | A Collection of Jini Technology Helper Utilities and Services Specifications |