SD.5. Supporting Interfaces and Classes

The ServiceDiscoveryManager utility class depends on the following interfaces defined in The Jini Technology Core Platform Specification,Lookup Service”: ServiceTemplate, ServiceItem, and ServiceMatches. This class also depends on a number of interfaces, each defined in this section; those interfaces are DiscoveryManagement, ServiceItemFilter, ServiceDiscoveryListener, and LookupCache.

The ServiceDiscoveryManager class references the following concrete classes: LookupDiscoveryManager and LeaseRenewalManager, each described in a separate chapter of this document, and ServiceDiscoveryEvent, which is defined in this chapter.

SD.5.1. The DiscoveryManagement Interface

Although it is not necessary for the ServiceDiscoveryManager itself to execute the discovery process, it does need to be notified when one of the lookup services it wishes to query is discovered or discarded. Thus, at a minimum, the ServiceDiscoveryManager requires access to the instances of DiscoveryEvent sent to the listeners registered with the event mechanism of the discovery process. The instance of DiscoveryManagement passed to the constructor of the ServiceDiscoveryManager provides a mechanism for acquiring access to those events. For a complete description of the semantics of the methods of this interface, refer to the Jini Discovery Utilities Specification.

One noteworthy item about the semantics of the ServiceDiscoveryManager is the effect that invocations of the discard method of DiscoveryManagement have on any cache objects created by the ServiceDiscoveryManager. The DiscoveryManagement interface specifies that the discard method will remove a particular lookup service from the managed set of lookup services already discovered, allowing that lookup service to be rediscovered. Invoking this method will result in the flushing of the lookup service from the appropriate cache. This effect ultimately causes a discard notification to be sent to all DiscoveryListener objects registered with the event mechanism of the discovery process (including all listeners registered by the ServiceDiscoveryManager).

The receipt of an event notification indicating that a lookup service from the managed set has been discarded must ultimately result in the cancellation and removal of all event leases that were granted by the discarded lookup service and that are managed by the LeaseRenewalManager on behalf of the ServiceDiscoveryManager.

Furthermore, every service reference stored in the cache that is registered with the discarded lookup service but is not registered with any of the remaining lookup services in the managed set will be “discarded” as well. That is, all previously discovered service references that are registered with only unavailable lookup services will be removed from the cache and made eligible for service rediscovery.

SD.5.2. The ServiceItemFilter Interface

The ServiceItemFilter interface defines the methods used by an object such as the ServiceDiscoveryManager or the LookupCache to apply additional matching criteria when searching for services in which an entity has registered interest. It is the responsibility of the entity requesting the application of additional criteria to construct an implementation of this interface that defines the additional criteria, and to pass the resulting object (referred to as a filter) into the object that will apply it.

The filtering mechanism provided by implementations of this interface is particularly useful to entities that wish to extend the capabilities of the standard template matching scheme. For example, because template matching does not allow one to search for services based on a range of attribute values, this additional matching mechanism can be exploited by the entity to ask the managing object to find all registered printer services that have a resolution attribute between say, 300 dpi and 1200 dpi.

package net.jini.lookup; 

public interface ServiceItemFilter {
    public boolean check(ServiceItem item); 
} 

SD.5.2.1. The Semantics

The check method defines the implementation of the additional matching criteria to apply to a ServiceItem object found through standard template matching. This method takes one argument: the ServiceItem object to test against the additional criteria. This method returns true if the input object satisfies the additional criteria and false otherwise.

Neither a null reference nor a ServiceItem object containing null fields will be passed into this method by the ServiceDiscoveryManager.

If the parameter input to this method is a ServiceItem object that has non-null fields but is associated with attribute sets containing null entries, this method must process that parameter in a reasonable manner.

Should an exception occur during an invocation of this method, the semantics of how that exception is handled are undefined.

This method must not modify the contents of the input ServiceItem object because it could result in unpredictable and undesirable effects on future processing by the ServiceDiscoveryManager. That is why the effects of any such modification to the contents of that input parameter are undefined.

SD.5.3. The ServiceDiscoveryEvent Class

The ServiceDiscoveryEvent class encapsulates the service discovery information made available by the event mechanism of the LookupCache. All listeners that an entity has registered with the cache’s event mechanism will receive an event of type ServiceDiscoveryEvent upon the discovery, removal, or modification of one of the cache’s services, as described previously in “Events and the Cache.”

This class is a subclass of the class EventObject. In addition to the methods of the EventObject class, this class provides two additional accessor methods that can be used to retrieve the additional state associated with the event: getPreEventServiceItem and getPostEventServiceItem.

The getSource method of the EventObject class returns the instance of LookupCache from which the given event originated.

package net.jini.lookup; 

public class ServiceDiscoveryEvent extends EventObject {
    public ServiceDiscoveryEvent(Object source, 
                                 ServiceItem preEventItem, 
                                 ServiceItem postEventItem) 
                                                {...} 

    public ServiceItem getPreEventServiceItem() {...} 
    public ServiceItem getPostEventServiceItem() {...} 
} 

SD.5.3.1. The Semantics

The constructor of ServiceDiscoveryEvent takes three arguments:

  • An instance of Object corresponding to the instance of LookupCache from which the given event originated

  • A ServiceItem reference representing the state of the service (associated with the given event) prior to the occurrence of the event

  • A ServiceItem reference representing the state of the service after the occurrence of the event

If null is passed as the source parameter for the constructor, a NullPointerException will be thrown.

Depending on the nature of the discovery event, a null reference may be passed as one or the other of the remaining parameters, but never both. If null is passed as both the preEventItem and the postEventItem parameters, a NullPointerException will be thrown.

Note that the constructor will not modify the contents of either ServiceItem argument. Doing so can result in unpredictable and undesirable effects on future processing by the ServiceDiscoveryManager. That is why the effects of any such modification to the contents of either input parameter are undefined.

The getPreEventServiceItem method returns an instance of ServiceItem containing the service reference corresponding to the given event. The service state reflected in the returned service item is the state of the service prior to the occurrence of the event.

If the event is a discovery event (as opposed to a removal or modification event), then this method will return null because the discovered service had no state in the cache prior to its discovery.

The getPostEventServiceItem method returns an instance of ServiceItem containing the service reference corresponding to the given event. The service state reflected in the returned service item is the state of the service after the occurrence of the event.

If the event is a removal event, then this method will return null because the discovered service has no state in the cache after it is removed from the cache.

Because making a copy can be a very expensive process, neither accessor method returns a copy of the service reference associated with the event. Rather, each method returns the appropriate service reference from the cache itself. Due to this cost, listeners (see Section SD.5.4, “The ServiceDiscoveryListener Interface” below) that receive a ServiceDiscoveryEvent must not modify the contents of the object returned by these methods; doing so could cause the state of the cache to become corrupted or inconsistent because the objects returned by these methods are also members of the cache. This potential for corruption or inconsistency is why the effects of modifying the object returned by either accessor method are undefined.

SD.5.4. The ServiceDiscoveryListener Interface

The ServiceDiscoveryListener interface defines the methods used by objects such as a LookupCache to notify an entity that events of interest related to the elements of the cache have occurred. It is the responsibility of the entity wishing to be notified of the occurrence of such events to construct an object that implements the ServiceDiscoveryListener interface and then register that object with the cache’s event mechanism. Any implementation of this interface must define the actions to take upon receipt of an event notification. The action taken is dependent on both the application and the particular event that has occurred.

package net.jini.lookup; 

public interface ServiceDiscoveryListener {
    public void serviceAdded(ServiceDiscoveryEvent event); 
    public void serviceRemoved(ServiceDiscoveryEvent event); 
    public void serviceChanged(ServiceDiscoveryEvent event); 
} 

SD.5.4.1. The Semantics

As described previously in the section titled “Events and the Cache,” when the cache receives from one of the managed lookup services, an event signaling the registration of a service of interest for the first time (or for the first time since the service has been discarded), the cache invokes the serviceAdded method on all instances of ServiceDiscoveryListener that are registered with the cache; doing so notifies the entity that a service of interest has been discovered. The method serviceAdded takes one argument: an instance of ServiceDiscoveryEvent containing references to the service item correspond ing to the event, including representations of the service’s state both before and after the event.

When the cache receives, from a managed lookup service, an event signaling the removal of a service of interest from the last such lookup service with which it was registered, the cache invokes the serviceRemoved method on all instances of ServiceDiscoveryListener that are registered with the cache; doing so notifies the entity that a service of interest has been discarded. The serviceRemoved method takes one argument: a ServiceDiscoveryEvent object containing references to the service item corresponding to the event, including representations of the service’s state both before and after the event.

When the cache receives, from a managed lookup service, an event signaling the unique modification of the attributes of a service of interest (across the attribute sets of all references to the service), the cache invokes the serviceChanged method on all instances of ServiceDiscoveryListener that are registered with the cache; doing so notifies the entity that the state of a service of interest has changed. The serviceChanged method takes one argument: a ServiceDiscoveryEvent object containing references to the service item corresponding to the event, including representations of the service’s state both before and after the event.

Should an exception occur during an invocation of any of the methods defined by this interface, the semantics of how that exception is handled are undefined.

Each method defined by this interface must not modify the contents of the ServiceDiscoveryEvent parameter; doing so can result in unpredictable and undesirable effects on future processing by the ServiceDiscoveryManager. It is for this reason that if one of these methods modifies the contents of the parameter, the effects are undefined.

This interface makes the following concurrency guarantee: for any given listener object that implements this interface, no two methods (either the same two methods or different methods) defined by the interface can be invoked at the same time by the same cache. For example, the serviceRemoved method must not be invoked while the invocation of another listener’s serviceAdded method is in progress.

Finally, it should be noted that the intent of the methods of this interface is to allow the recipient of the ServiceDiscoveryEvent to be informed that a service has been added to, removed from, or modified in the cache. Calls to these methods are synchronous to allow the entity that makes the call (for example, a thread that interacts with the various lookup services of interest) to determine whether or not the call succeeded. However, it is not part of the semantics of the call that the notification return can be delayed while the recipient of the call reacts to the occurrence of the event. It is therefore highly recommended that implementations of this interface avoid time consuming operations and return from the method as quickly as possible. For example, one strategy might be to simply note the occurrence of the ServiceDiscoveryEvent and perform any time-consuming event handling asynchronously.

SD.5.5. The LookupCache Interface

The LookupCache interface defines the methods provided by the object created and returned by the ServiceDiscoveryManager when an entity invokes the createLookupCache method. Within this object are stored the discovered service references that match criteria defined by the entity. Through this interface the entity may retrieve one or more of the stored service references, register and unregister with the cache’s event mechanism, and terminate all of the cache’s processing.

package net.jini.lookup; 

public interface LookupCache {
    public ServiceItem   lookup(ServiceItemFilter filter); 

    public ServiceItem[] lookup(ServiceItemFilter filter, 
                                int maxMatches); 

    public void addListener 
                         (ServiceDiscoveryListener listener); 
    public void removeListener 
                         (ServiceDiscoveryListener listener); 

    public void discard(Object serviceReference); 

    public void terminate(); 
} 

SD.5.5.1. The Semantics

Depending on which version is invoked, the lookup method of the LookupCache interface returns one or more elements—each matching the input criteria—that were stored in the associated cache. The object that is returned is either a single instance of ServiceItem or a set of service references in the form of an array of ServiceItem objects. Each service item that is returned by either form of this method must have been previously discovered both to be registered with one or more of the lookup services in the managed set and to match criteria defined by the entity.

One argument is common to both forms of lookup: an instance of ServiceItemFilter. The semantics of the filter argument are identical to those of the filter argument specified for a number of the methods defined in the interface of the ServiceDiscoveryManager utility class. This argument is intended to allow an entity to separate its filtering into two steps: an initial filter applied during the discovery phase and then a finer resolution filter applied upon retrieval from the cache. As with the methods of the ServiceDiscoveryManager, if null is the value of this argument, then no additional filtering will be performed.

The second form of the lookup method of the LookupCache interface takes an additional argument: a parameter of type int that represents the maximum number of matches that should be returned. The array returned by this form of lookup will contain no more than the requested number of service references, although it may contain fewer than that number. The value input to this argument must be positive; otherwise, an IllegalArgumentException will be thrown.

If the cache is empty, or if no service can be found that matches the input criteria, then the first form of lookup will return null, whereas the second form of lookup will return an empty array. The algorithm used to select the return element(s) from the set of matching service references is implementation dependent.

Neither form of the lookup method of the LookupCache interface returns a copy of the matching service reference(s) that were selected; rather, each form returns the actual service reference(s) from the cache itself. Because the actual service reference(s) are returned, entities that invoke either form of this method must not modify the contents of the returned reference(s). Modifying the returned service reference(s) could cause the state of the cache to become corrupted or inconsistent. This potential for corruption or inconsistency is why the effects of modifying the service reference(s) returned by either form of lookup is undefined.

Typically, an entity will request the creation of a separate cache for each service type of interest. When the entity simply needs a reference to a service of a particular type, the entity should invoke the first form of lookup to retrieve one element from the cache; in this case, which particular service reference that is returned will not, in general, matter to the entity. If for some reason it does matter to an entity which service reference is returned, then the entity can invoke the second form of lookup requesting that Integer.MAX_VALUE service references be returned; doing so will return all elements of the cache that match the input criteria. The entity can then iterate through each element, selecting the desired reference.

The addListener method will register a ServiceDiscoveryListener object with the event mechanism of a LookupCache. This listener object will receive a ServiceDiscoveryEvent upon the discovery, removal, or modification of one of the cache’s services, as described previously in “Events and the Cache.” This method takes one argument: a reference to the ServiceDiscoveryListener object to register.

If null is input to the addListener method, a NullPointerException is thrown. If the object input is a duplicate (using the equals method) of another element in the set of listeners, no action is taken.

Once a listener is registered, it will be notified of all service references discovered to date, and will be notified as new services are discovered and existing services are modified or discarded.

The LookupCache makes a reentrancy guarantee with respect to any ServiceDiscoveryListener objects registered with it. Should the LookupCache invoke a method on a registered listener (a local call), any call from that method to a local method of the LookupCache is guaranteed not to result in a deadlock condition.

The removeListener method will remove a ServiceDiscoveryListener object from the set of listeners currently registered with a LookupCache. Once all listeners are removed from the cache’s set of listeners, the cache will send no more ServiceDiscoveryEvent notifications. This method takes one argument: a reference to the ServiceDiscoveryListener object to remove.

If the parameter value to removeListener is null, or if the listener passed to this method does not exist in the set of listeners maintained by the implementation class, then this method will take no action.

If an entity determines that a service reference retrieved from the cache is no longer available, the entity should request the removal of that reference from the cache. The mechanism for discarding an unavailable service from the cache is provided by the discard method of the LookupCache interface. The discard method takes one argument: an instance of Object whose reference is the service reference to remove from the cache. If the proxy input to this method is null, or if it matches (using the equals method) none of the service references in the cache, this method takes no action.

The discard method not only deletes the service reference from the cache, but also causes a notification to be sent to all registered listeners indicating that the service has been discarded (see the description of the serviceRemoved method in the section that specifies the ServiceDiscoveryListener interface). The service is guaranteed to have been removed from the cache when this method completes successfully; the service is then said to have been discarded. No such guarantee is made with respect to when the discard event is sent to the client’s registered listeners. That is, the event that notifies the client that the service has been discarded may or may not be sent asynchronously.

With respect to discarding services, there is a situation that must be handled by all implementations of the LookupCache. Because the LookupCache discovers a service through a lookup service rather than through the service itself, there is a danger that, unless the LookupCache takes action (described below), once a service has been discarded, it may never be rediscovered. This can happen because even though a service may be discarded from the cache, it may not be discarded from the lookup services with which it is registered.

To understand this situation, it might help to first consider the conditions under which a service is normally discarded from the cache and then rediscovered. An entity typically discards a service when the entity determines that the service has become unavailable. Recall that a service usually becomes unavailable to an entity when the service crashes, the service is shut down, or the link between the entity and the service experiences a network partition. Under normal circumstances, when a well-defined service becomes unavailable because it has crashed or has been shut down, and the entity—after determining that the service is unavailable—discards the service, the cache will rediscover the service when the service comes back on line. The service is rediscovered because a well-behaved service will typically reregister with each lookup service with which it was registered prior to crashing or shutting down. Note that such a service will reregister even when its original lease with a lookup service is still valid. When the service reregisters with a lookup service, the lookup service notifies the cache’s listener that a reregistration has occurred, and the service is then rediscovered.

A special case of the scenario just described involves services that choose to persist their leases. Typically, when a service that persists its leases comes back on line after a crash or a shutdown, the service will not reregister with any lookup service for which the associated lease is still valid. If none of the service’s leases expire during the period in which the service is down, then when the service comes back on line, it will never reregister with any of the desired lookup services, and the cache will never be notified that the discarded service has become available once again.

Therefore it is important to note that there are conditions that may hinder rediscovering certain types of services that were discarded as a result of a crash or shutdown. This situation should not occur with any frequency because services that persist their leases are expected to be less common than other types of services. However, there is a common scenario in which any type of service may be discarded but never rediscovered. This new scenario is characterized not by service crashes or shutdowns, but by communication failures. In this situation, communication failures cause only the entity to view the service as unavailable; that is each lookup service in the managed set can still communicate with the service.

As with service crashes or shutdowns, communication failures between the entity and the service can also cause the entity to discard the service. But prob lems can arise when the communication failures occur between the entity and the service, but not between the service and any of the lookup services in the managed set. Although the service never goes down, it is still discarded by the entity because the inability to communicate with the service causes the entity to view the service as unavailable. But because the service can still communicate with the lookup services, the service will continue renewing its residency in each lookup service. Thus, since none of the service’s leases expire, the service never reregisters with any of the lookup services, and the lookup services will never send events to the cache’s listener that cause the service to be rediscovered.

To address the scenarios described above, all implementations must do the following when a service is discarded from the cache:

  • Place the reference to the discarded service in separate storage, and remove the reference from the cache’s storage (to guarantee that subsequent queries of the cache do not return that same unavailable reference).

  • Wait an implementation-dependent amount of time that is likely to exceed the typical service lease duration.

  • If a ServiceEvent with a transition equal to TRANSITION_MATCH_NOMATCH is received (indicating that the service’s lease has expired), then the service reference that was set aside can be flushed, and the service is then truly discarded.

  • If such a ServiceEvent is not received (indicating that a transient communication failure probably occurred), the service reference that was set aside should be placed back in the cache’s local storage, and if the entity is registered for events from the cache, the appropriate event should be sent to the entity’s registered listener.

The terminate method performs cleanup duties related to the termination of the processing being performed by a particular instance of LookupCache. For that instance, this method cancels all event leases granted by the lookup services that supplied the contents of the cache, and unexports all remote listener objects registered with those lookup services. The terminate method is typically called when the entity is no longer interested in the contents of the LookupCache. Upon completion of the termination process, the semantics of all current and future method invocations on the current instance of LookupCache are undefined.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.227.82