SD.4. The Semantics

The ServiceDiscoveryManager makes certain concurrency guarantees with respect to the methods it defines. When a method of ServiceDiscoveryManager invokes a remote method, although such an invocation may block other remote calls made in the ServiceDiscoveryManager, invocations of local methods will not be blocked.

SD.4.1. The Methods

The ServiceDiscoveryManager helper utility class defines a number of public methods in addition to its constructor. This utility defines a factory method that allows the entity to create a local cache for storing references to desired services that have been previously discovered. Additionally, this class defines a set of methods that the entity may use to query (remotely) each discovered lookup service for other services that are of interest to the entity.

The equals method for the ServiceDiscoveryManager class returns true if and only if two instances of this class refer to the same object. That is, x and y are equal instances of this class if and only if x==y has the value true.

SD.4.1.1. The Constructor

The constructor of the ServiceDiscoveryManager takes two arguments: an object that implements the DiscoveryManagement interface and a reference to a LeaseRenewalManager object. The constructor throws an IOException because construction of a ServiceDiscoveryManager may initiate the multicast discovery process, a process that can throw IOException.

To use the ServiceDiscoveryManager, an entity supplies an object through which notifications that indicate a lookup service has been discovered or discarded will be received. At a minimum, this object must satisfy the contract defined in the DiscoveryManagement interface. That is, this object must provide the ServiceDiscoveryManager with the ability to set discovery listeners and to discard previously discovered lookup services when they are found to be unavailable.

A value of null may be passed as the DiscoveryManagement argument. If the value of the argument is null, an instance of the LookupDiscoveryManager utility class will be constructed to discover only those lookup services that are members of the public group.

A value of null may be passed as the LeaseRenewalManager argument. If the value of the argument is null, an instance of the LeaseRenewalManager class will be created, initially managing no Lease objects.

SD.4.1.2. The createLookupCache Method

The createLookupCache method allows an entity to request that the ServiceDiscoveryManager create a new managed set (or cache) and populate it with services, which match criteria defined by the entity, and whose references are registered with one or more of the lookup services the entity has targeted for discovery.

This method returns an object of type LookupCache. Through this return value, the entity can query the cache for services of interest, manage the cache’s event mechanism for service discoveries, or terminate the cache. The definition of the LookupCache interface is presented later in this specification.

An entity typically uses the object returned by this method to provide local storage of, and access to, references to services that it is interested in using. Entities that need frequent access to numerous services will find the object returned by this method quite useful because acquisition of those service references is provided through local method invocations. Additionally, because the object returned by this method provides an event mechanism, it is also useful to entities wishing to simply monitor, in an event-driven manner, the state changes that occur in the services of interest.

The createLookupCache method takes three arguments: an instance of ServiceTemplate, an instance of ServiceItemFilter, and an instance of ServiceDiscoveryListener. Both the interfaces ServiceItemFilter and ServiceDiscoveryListener are presented later in this chapter.

Together, the tmpl and the filter arguments define the criteria with which service-matching should be performed. The listener argument references an object that will receive notifications when services matching the input criteria are discovered for the first time, or have encountered a state change such as removal from all lookup services or attribute set changes. If null is input to the listener argument for a particular invocation of this method, the cache resulting from that invocation will send no such notifications.

The tmpl argument employs template matching semantics that are identical to the semantics described in The Jini Technology Core Platform Specification,ServiceTemplate and Item Matching”) to identify the service(s) to acquire from lookup services in the managed set. The object passed to the filter argument is then used to apply additional matching criteria to any service references found through template matching. The additional matching criteria defined by the filter parameter are application-specific, and therefore must be defined by the client-like entity itself (as described in Section SD.5.2, “The ServiceItemFilter Interface”). Furthermore, once an instance of the cache is created, the filter associated with that instance will not change during the life of that particular cache. If the filter is changed so that its original behavior is modified, the effect on the cache is undefined.

As a convenience, a null reference input to the tmpl argument is treated as equivalent to inputting a ServiceTemplate constructed with all null arguments (all wildcards). That is, the cache will attempt to discover all services contained in each lookup service in the managed set. If a null value is passed as the filter argument, then only template matching will be employed to find the desired services.

Entities that invoke this method must take care not to modify the contents of the object input through the tmpl parameter after the cache has been created. Doing so could cause the state of the cache to become corrupted or inconsistent. It is for this reason that the effects of modifying the contents of the tmpl parameter, after this method is invoked, are undefined.

Events and the Cache

To keep its contents up to date, the cache must register with the event mechanism of each lookup service in the managed set. From the point of view of the cache, a service is “discovered” when it receives a remote event from one of those lookup services notifying the cache of the existence of a service matching the input criteria. In addition, whenever one of the cache’s discovered services experiences a state change in one of the lookup services in which it is registered, the cache will receive a remote event identifying that state change whenever the change satisfies the matching criteria.

For a number of reasons the cache may receive multiple events corresponding to the same Jini service. For example, a particular Jini service may be registered with more than one lookup service from the managed set. If the cache requests events from each lookup service using a template configured with no restriction along the service ID search axis and little or no restriction along the attribute search axis, the cache will receive a notification each time one of the following events occurs at any of the those lookup services:

  • The service, matching the template, is registered with one of the lookup services.

  • The lease of the matching service is cancelled or expires.

  • An attribute set associated with the matching service is modified in some way.

Just as the cache requests that it be notified of state changes in matching services occurring within each lookup service, an entity may request that the cache deliver events that indicate analogous state changes in the service references stored in the cache.

There are two significant differences in the event mechanism between the lookup services and the cache, and the event mechanism between the cache and the client-like entity. First and foremost, the events sent from the lookup services to the cache are remote events, whereas the events sent from the cache to the entity are local events. Second, each registration or state-change event sent from the cache to the entity may actually have been a result of multiple corresponding events received by the cache from a set of lookup services. Thus, there is a many-to-one relationship between the events received by the cache and the events sent by the cache.

For many entities that use the cache’s event mechanism to interact with the cache’s discovered services, knowledge of the number of distinct service references, as well as identification of the lookup services with which those references are registered, is of no interest. Such entities typically are interested only in acquiring a reference—not all references—to the desired services. Thus, the relationship between the two event mechanisms described previously allows the ServiceDiscoveryManager to hide the lookup services with which the cache interacts from the entity. For entities that are interested in the additional information, the cache provides methods separate from the event mechanism for obtaining such information.

To summarize, although the cache may receive multiple events signaling a state change related to a particular matching service, the cache will typically send only a single corresponding event to the entity. That is, for any matching service:

  • The cache will send a service discovery event to the entity only once: after the cache acquires the first reference to the matching service.

  • The cache will send a service removal event to the entity only once: after every reference to the service has had its lease expire or cancelled; that is, only after all references to the matching service have been removed from every lookup service in the cache’s managed set.

  • For each set of event(s) notifying the cache that a particular modification has been made to the attribute set associated with one of the service references, one service modification event will be sent to the entity, but only if the attribute set state reflected in the received event represents an actual change in the service’s current attribute set state (as maintained by the cache).

With respect to the state of the attribute sets associated with the service references stored in the cache, the cache should be viewed as maintaining a single attribute set state for each collection of service references that represent the same service. That single state will always be equivalent to the state reflected in the last attribute set modification event received by the cache.

For example, suppose each of three different references to a service that matches the input criteria is registered with three lookup services in the managed set. Suppose the attribute sets associated with each service reference are modified in exactly the same way. For this specific case, the cache would receive three events—one from each lookup service—signaling these modifications. Upon receipt of the first event, the cache modifies its current notion of the service’s attribute set state, and then notifies the entity of the change, but only if the state reflected in the event represents a change in the current state. Because the remaining two events received by the cache represent the same state change as that represented in the first event, the cache sends no other notification.

Next, suppose a second modification, different from the first, is made on only two of the service references, and a third unique modification is made on the remaining service reference. In this case, the cache will still receive three events, but how the cache handles the events is dependent on the order of arrival of the events. For simplicity, call the three events e1, e2, and e3. Use s to represent the cache’s current notion of the service’s attribute set state, and use s1 and s2 to represent the states resulting after each attribute modification has occurred. In this example, e1 and e2 will be sent to the cache after the each of the service’s attribute sets is modified to s1 in their respective lookup services. Event e3 is sent after the service’s attribute sets are modified to s2 in the remaining lookup service.

If the order of arrival is e1, e2, and then e3, the cache will change s into s1 and notify the entity after the arrival of e1 but will do nothing upon the arrival of e2. Upon the arrival of e3, the cache will change s (which is now s1) into s2. If the order of arrival of the events is e1, e2, and then e2, the cache will first change s into s1, then into s2, and then back into s1 again. Furthermore, for each state change made, the cache will send a notification to the entity.

Thus, the events generated by the cache’s event mechanism and sent by the cache to the entity are more representative of the state changes that occur in the cache than in the lookup services.

An entity may register for events from the cache in one of two ways. The entity may supply an instance of ServiceDiscoveryListener to the listener argument of the createLookupCache method, or it may invoke a method on the cache to add a listener to the cache. Thus, an entity may register for events from the cache at any time during the execution life of the cache.

Similarly, the cache provides a method that an entity, which is currently registered for events from the cache, may use at any time to unregister with the cache’s event mechanism.

SD.4.1.3. The lookup Method

The lookup method queries each available lookup service in the managed set for service reference(s) that match criteria defined by the entity that invokes this method. Entities typically employ this method when they need infrequent access to services and when the cost of making remote queries is outweighed by the overhead of maintaining a local cache (for example, because of resource limitations).

The lookup method has four versions, each version falling into one of two categories: those versions of this method that return a single instance of ServiceItem and those versions that return a set of service references as an array of ServiceItem objects.

Two arguments are common to all versions of this method: an instance of ServiceTemplate and an instance of ServiceItemFilter.

Within each category, the versions of lookup differ only in whether or not a particular version provides what is referred to as a “wait” (or blocking) feature. That is, each category contains both a non-blocking version of lookup which returns immediately when unable to find the desired service, and a blocking version which returns only after waiting a specified amount of time for the desired service to be discovered. The particular version of lookup that an entity employs is typically determined by the entity’s intended usage pattern.

The descriptions that follow refer to all versions of the lookup method, except where explicitly noted.

The tmpl argument and the filter argument both have semantics identical to that defined for these arguments in the description of the createLookupCache method above. In particular,

  • A null reference value for the tmpl parameter is treated as the equivalent of a “wildcarded” ServiceTemplate.

  • If null is the value for the filter parameter, only template matching will be employed to find the desired services.

  • The effects of modifying the contents of the tmpl parameter while the invocation is in progress are unpredictable and undefined.

If no service can be found that matches the desired criteria, then the versions of lookup from the first category—those that return a single instance of ServiceItem—will return null, whereas the versions from the second category—those that return an array of ServiceItem instances—will return an empty array.

The versions of lookup from the first category can be used in a fashion similar to the first form of the lookup method defined in the ServiceRegistrar interface described in The Jini Technology Core Platform Specification,Lookup Service”. That is, an entity would typically invoke one of these versions of lookup when it wishes to find a single service reference and the particular lookup service with which that service reference is registered is unimportant to the entity.

Each version of lookup defined in the ServiceDiscoveryManager differs with the corresponding version of lookup in ServiceRegistrar in the following ways:

  • The versions of lookup defined in the ServiceDiscoveryManager query multiple lookup services (the order in which the lookup services are queried is dependent on the implementation).

  • The versions of lookup defined in the ServiceDiscoveryManager can apply additional matching criteria, in the form of a filter object, when deciding whether a service reference found through standard template matching should be returned to the entity.

The versions of lookup that return an array of ServiceItem objects can be used in a fashion similar to the second form of lookup defined in the ServiceRegistrar interface. That is, an entity would typically invoke these versions of lookup when it wishes to find multiple service references matching the input criteria. Each of the versions of lookup that return an array of ServiceItem objects takes as one of its arguments an int parameter, maxMatches, that represents the maximum number of matches that should be returned. The array returned by these methods will contain no more than maxMatches service references, although it may contain fewer than that number.

As with the versions of lookup that return a single instance of ServiceItem, multiple queries and filtering are also notable differences between the second-category versions of this method and their counterpart in ServiceRegistrar.

For each version of lookup, whenever a lookup service query returns a null service reference, the filter is bypassed, and the service reference is excluded from the return object. On the other hand, if the query returns a nonnull service reference in which the associated array of attribute contains one or more null elements, the filter is still applied and the service reference is included in the return object.

Each version of lookup may be confronted with duplicate references during a search for a service of interest. This is because the same service may register with more than one lookup service in the managed set. As with the cache, when a set of service references is returned by lookup, each service reference in the return set will be unique with respect to all other service references in the set, as determined by the equals method provided by each reference.

If it is determined that a lookup service is unavailable (due to an exception or some other non-fatal error) while interacting with a lookup service from the managed set, all versions of lookup will invoke the discard method on the instance of DiscoveryManagement being employed by the ServiceDiscoveryManager. Doing so will result in the unavailable lookup service being discarded and made eligible for rediscovery.

Recall that the propagation of modifications to a service’s attributes across a set of lookup services typically occurs asynchronously. It is for this reason that while invoking lookup to find a set of matching services, it is possible that the set returned may contain multiple references having the same service ID with different attributes. Note that although this sort of inconsistent state can also occur if the entity employs a cache, the cache will eventually reflect the correct state.

The Blocking Feature of lookup

As noted above, each category contains a version of lookup that provides a feature in which the entity can request that if the number of service references found throughout the available lookup services does not fall into a desired range, the method will wait a finite period of time until either an acceptable minimum number of service references are discovered or the specified time period has passed.

The versions of lookup providing this blocking feature each takes as one of its parameters a value of type long that represents the number of milliseconds to wait for the service to be discovered. In addition to RemoteException, each of these versions of lookup may throw an InterruptedException.

One of these blocking versions of lookup implicitly uses a value of one for both the acceptable minimum and the allowable maximum number of service references to discover. The other blocking version requires that the entity specify the range through the minMatches and maxMatches parameters, respectively.

Prior to blocking, each of these versions of lookup first queries each available lookup service in an attempt to retrieve a satisfactory number of matching services. Whether or not the method actually blocks is dependent on how many matching service references are found during the query process. Blocking occurs only if after querying all of the available lookup services, the number of matching services found is less than the acceptable minimum. If the waiting period (measured from when blocking first begins) passes before that minimum number of service references is found, the method will return the service references that have been discovered up to that point. If the waiting period passes and no services have been found, null or an empty array (depending on the version of lookup) will be returned.

If, after querying all of the available lookup services, the number of matching services found is greater than or equal to the specified minimum but less than the specified maximum, the method will return the currently discovered service references without blocking. If the initial query process produces the desired maximum number of service references, the method will return the results immediately.

The blocking versions of lookup are quite useful to entities that cannot proceed until such a service of interest is found. If a non-positive value is input to the waitDur argument, then the method will not wait. It will simply query the available lookup services and employ the return semantics described above.

The values of the minMatches and maxMatches arguments must both be positive, and maxMatches must be greater than or equal to minMatches; otherwise, an IllegalArgumentException will be thrown.

The blocking versions of lookup make a concurrency guarantee with respect to the discovery of new lookup services during the wait period. That is, while waiting for matching service reference(s) to be discovered, if one or more of the desired—but previously unavailable—lookup services is discovered and added to the managed set, those new lookup services will also be queried for the service(s) of interest.

In addition, the blocking versions of lookup throw InterruptedException. When an entity invokes either version with valid parameters, the entity may decide during the wait period that it no longer wishes to wait the entire period for the method to return. Thus, while the method is blocking on the discovery of matching service(s), it may be interrupted by invoking the interrupt method from the Thread class. The intent of this mechanism is to allow the entity to interrupt a blocking lookup in the same way it would a sleeping thread.

SD.4.1.4. The getDiscoveryManager Method

The getDiscoveryManager method returns an object that implements the DiscoveryManagement interface. The object returned by this method provides the ServiceDiscoveryManager with the ability to set discovery listeners and to dis card previously discovered lookup services when they are found to be unavailable. This method takes no arguments.

SD.4.1.5. The getLeaseRenewalManager Method

The getLeaseRenewalManager method returns a LeaseRenewalManager object. The object returned by this method manages the leases requested and held by the ServiceDiscoveryManager. In general, these leases correspond to the registrations made by the ServiceDiscoveryManager with the event mechanism of each lookup service in the managed set. This method takes no arguments.

SD.4.1.6. The terminate Method

The terminate method performs cleanup duties related to the termination of the event mechanism for lookup service discovery, the event mechanism for service discovery, and the cache management duties of the ServiceDiscoveryManager. That is, the terminate method will terminate each LookupCache instance created and managed by the ServiceDiscoveryManager. Additionally, if the discovery manager employed by the ServiceDiscoveryManager was created by the ServiceDiscoveryManager itself, then the terminate method will also terminate that discovery manager.

Note that if the discovery manager was created externally and supplied to the ServiceDiscoveryManager, then any reference to that discovery manager held by the entity will remain valid, even after the ServiceDiscoveryManager has been terminated. Similarly, if the entity holds a reference to the lease renewal manager employed by the ServiceDiscoveryManager, that reference will also remain valid after termination, whether lease renewal manager was created externally or by the ServiceDiscoveryManager itself.

The ServiceDiscoveryManager makes certain concurrency guarantees with respect to an invocation of terminate while other method invocations are in progress. The termination process described above will not begin until completion of all invocations of the public methods defined in the public interface of ServiceDiscoveryManager; that is, until completion of invocations of createLookupCache, lookup, getDiscoveryManager, and getLeaseRenewalManager.

Upon completion of the termination process, the semantics of all current and future method invocations on the terminated instance of the ServiceDiscoveryManager are undefined.

SD.4.2. Defining Service Equality

The ability to accurately determine when two different service references are equal is very important to the ServiceDiscoveryManager in general, and the LookupCache in particular. Any restriction placed on that ability can result in inefficient and undesirable behavior. Storing and managing duplicate service references—that is, proxies that refer to the same version of the same back end service—is usually viewed as undesirable. In other words, when storing and managing service references, it is very desirable to be able to determine not only that two different proxies refer to the same back end service, but if they do refer to the same back end, whether or not the current version of the referenced service has been replaced with a new version.

The mechanism employed by the LookupCache to avoid storing duplicate service references is the equals method provided by the discovered services themselves. This is because an individual well-behaved service of interest will usually register with multiple lookup services, and for each lookup service with which that service registers, the LookupCache will receive a separate event containing a reference to the service. When the LookupCache receives events from multiple lookup services, the service ID (retrieved from the service reference in the event) together with the equals method provided by the service itself, is used to distinguish the service references from each other. In this way, when a new event arrives containing a reference associated with the same service as an already-stored reference, the LookupCache can determine whether the new reference is a duplicate or the service has been replaced with a new version of itself. In the former case, the duplicate would be ignored; in the latter case, the old reference would be replaced with the new reference.

Thus, the LookupCache relies on the provider of each service to override the equals method inherited from the class Object with an implementation that allows for the identification of duplicate service proxies. In addition to the equals method, each service should also provide a proper implementation of the hashCode method. This is because even if an entity never explicitly calls on the equals method to compare service references, those references may still be stored in container classes (for example, Hashtable) where such comparisons are made “under the covers.” From the point of view of the ServiceDiscoveryManager and the LookupCache, providing an appropriate implementation for both the equals method and the hashCode method is a key characteristic of good behavior in a Jini service.

Note that there is no need to override either the equals method or the hash-Code method if the service is implemented as a purely remote object in which the service proxy is an RMI stub. In this case, appropriate implementations for both methods are already provided in the stub.

SD.4.3. Exporting RemoteEventListener Objects

A subset of the methods on the ServiceDiscoveryManager, when invoked, will result in a request for registration with the event mechanism of one or more lookup services. The methods that result in such a request are createLookupCache and the blocking versions of the lookup method.

Any entity that invokes one of these methods must export, to each lookup service with which a registration occurs, the stub classes of the RemoteEventListener object through which instances of RemoteEvent will be received. Furthermore, each of these methods must throw RemoteException. The reasons that a RemoteException can occur fall into one of the following categories:

  • Each of these methods attempts to export a remote object, a process that can throw RemoteException.

  • Each of these methods attempts to register with the event mechanism of at least one lookup service, a process that can throw RemoteException.

How each of the affected methods handle the RemoteException is dependent on the reason for the exception. If a RemoteException (or any other non-fatal exception or error) is thrown during an attempt to register for events from a lookup service, that lookup service will be discarded and made eligible for rediscovery. On the other hand, if a RemoteException occurs during an attempt to export the listener, the method from which that attempt is made will re-throw the same exception.

The potential for RemoteException during the export process imposes the following requirement: the same instance of the listener must be exported to each lookup service from which events will be requested. Furthermore, the creation and export of the listener must occur prior to the event registration process. This requirement guarantees that should a RemoteException occur after the registration process has begun, the exception will not be propagated and event processing will continue.

To understand the significance of this requirement, consider the scenario in which a different instance of the listener is exported to each lookup service. If a new lookup service is discovered after the event process has begun for the other lookup services in the managed set, a new instance of the listener must be created and exported. Should a RemoteException occur during the export process, the exception will be propagated and all event processing will stop—a result that many entities may view as undesirable.

To facilitate exporting the listener, the entity—whether it is a Jini client or a Jini service—is responsible for providing and advertising a mechanism through which each lookup service will acquire the listener’s stub classes.

For example, one implementation of the ServiceDiscoveryManager might provide a special JAR file containing only the listener stub classes to optimize download time. By including this JAR file in the entity’s java.rmi.server.codebase property (in the appropriate format, specifying transport protocol and location), the entity advertises the mechanism that lookup services can employ to acquire the stub classes. By executing a process to serve up the JAR file (for example, an HTTP server), the mechanism through which each lookup service acquires those stub classes is provided.

It is important to note that should such a mechanism not be made available to each lookup service with which event registration will be requested, a “silent failure” can occur repeatedly. If the mechanism is not available, each lookup service cannot acquire the exported listener. Because each lookup service cannot acquire the exported listener, any attempts to register for events will fail. Whenever an attempt to register for events fails, the associated lookup service will be discarded and made eligible for rediscovery. Upon rediscovery of the discarded lookup service, the cycle repeats when a new attempt to register for events is made.

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

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