|
OverviewSome applications need to know when a new Entry is written to the space. For this reason, there is a standard notify method in the JavaSpaces API: EventRegistration notify(Entry template, Transaction txn, RemoteEventListener listener, long lease, MarshalledObject handback); A client that wants to receive notifications of new Entries arriving at the space prepares a template and uses the notify space method to register the template in the space. When a new Entry that matches the template arrives at the space, the notify method of the RemoteEventListener supplied in the registration is invoked, supplying the space with a RemoteEvent object. Do not confuse the JavaSpaces notify method, used for registering the template, with the notify method of the RemoteEventListener, that is a callback method invoked by the space.
The RemoteEventListener object supplied in the JavaSpaces notify method may be the client itself, or any other remote listener that the client wishes to receive the event. This gives enormous flexibility, and enables various event-fetching models, like filtering and polling. For example, a mobile client may use the Jini Mailbox Service to hold events until it reconnects to the network. The RemoteEventListener object is a remote object, and its stub is used by the space to invoke the notify callback. Hence, the proxy of the listener must be annotated with a suitable code base, so that the space can download it on demand. This usually means that the client or someone acting for the client should run an HTTP server to serve class files or jar files, and that the client should annotate the code base via the java.rmi.server.codebase system property. To ease the development and deployment of the notify method, a com.j_spaces.core.client.NotifyDelegator class is provided. This class provides several enhancements:
Here is the NotifyDelegator constructor signature: NotifyDelegator(IJSpace space, Entry template, Transaction txn, RemoteEventListener listener, long lease, MarshalledObject handback, boolean fifoEnabled, int notifyMask) Creates a new delegator that can receive ordered notifications.
Use Lease.FOREVER as Notify Registration Lease Time CarefullyRegistration for notifications is cancelled automatically when the notification object invalidates – i.e. is cleared by the garbage collector. With abnormal termination of the application, the garbage collector cannot finalize the registration object. This may lead to delays with delivering notifications to live clients, because the space accumulates notification registrations without the ability to clear these once they are invalidated. The space includes a mechanism that detects stale notify registration using the space schema notifier-retries parameter – once a notification can't be delivered to a client (network failure or a dead client), the space retries to send the notification several times (according the notifier-retries parameter value) and once it fails, the notify registration is removed. If there are many clients terminating their operation in an abnormal manner while having an active event registration, the space might need some time to detect all stale clients and their notify registrations, delaying notification delivery to existing live clients. The root cause of this behavior is the thread pool within the space engine that is responsible for delivering events to clients. When all pool threads are fully consumed, notification delivery time suffers, due to the time it takes to detect and remove all stale registrations.
To reduce the amount of stale registrations, register notification with a reasonable lease time (30 seconds - 2 minutes can be a good interval) and renew these using the net.jini.lease.LeaseRenewalManager every 30 seconds - 2 minutes. This ensures that once the client exists in an abnormal manner, the registration automatically expires and is removed, reducing the chance to fully consume the notification thread pool and delay notification delivery to live clients. Cancelling Notify RegistrationTo cancel notify registration:
Transient Notify RegistrationWhen running the space in persistent mode, you might want to have transient notify registrations. These registrations are not persistent, and aren't recovered once the space is restarted in case the notify registration has not expired. In this case, extend your class from MetaDataEntry and call the MetaDataEntry.makeTransient() as part of the template constructor. Stale Notify RegistrationWhen the space detects stale notify registration (clients that registered for notify registration do not respond), the notify registration is cancelled. When the space is running in persistent mode, removal of the registrations takes place also in the durable media (database/indexed file).
Below is and example for usage of the NotifyDelegator: public class HelloWorld implements RemoteEventListener { &.. // register a notification m_Space.snapshot(new Message()); m_Template = new Message(); Lease leases[] = new Lease[10]; // Registering for all Notifies using NOTIFY_ALL - i.e. : NOTIFY_WRITE , NOTIFY_UPDATE , NOTIFY_TAKE , NOTIFY_LEASE_EXPIRATION // Events will be delivered in FIFO Mode m_NotifyDelegator = new NotifyDelegator((IJSpace) m_Space, m_Template, null, this, Lease.FOREVER, null , true , NotifyModifiers.NOTIFY_ALL); System.out.println("Notification registered. Registration id: " + m_NotifyDelegator.getEventRegistration().getID() + " ; Sequence number: "+ m_NotifyDelegator.getEventRegistration().getSequenceNumber()); // write 5 messages to space System.out.println(getTime() + "Writing 5 messages to space..."); for (int i = 0; i < 5; i++) { Message msg = new Message(); msg .content = "Hello World " + i; leases [i] = m_Space.write(msg, null, 5000); System.out.println(getTime() + "Wrote entry " + i); } // update 5 messages in space System.out.println(getTime() + "Update 5 messages in space..."); for (int i = 0; i < 5; i++) { Message msg = new Message(); msg.content = "Hello World " + i; Message ret = (Message)m_Space.read(msg, null, 1000); m_Space.update(ret , null, Lease.FOREVER , 1000); System.out.println(getTime() + "update entry " + i); } // take 2 messages from space System.out.println(getTime() + "Take 2 messages from space..."); for (int i = 0; i < 2; i++) { Message msg = new Message(); msg.content = "Hello World " + i; Message ret = (Message)m_Space.take(msg, null, 1000); System.out.println(getTime() + "Take entry " + i); } // sleep Thread.sleep(5 * 5000); // Cancel Lease for 3 messages at space System.out.println(getTime() + "Cancel Lease for 3 messages in space..."); for (int i = 2; i < 5; i++) { leases[i].cancel(); System.out.println(getTime() + "Canceled Lease " + i); } } The client uses the NotifyDelegator to register for notifications on message Entries arriving to the space. The registrations are forever (using Lease.FOREVER), and all types of events are delivered to the registered client (NotifyModifiers.NOTIFY_ALL). Although developers can use notifications in a transactions context, this example uses notifications under a null transaction. When a notification is made inside a transaction context, the notify template is implicitly dropped in the end of the transaction. In the example above, the reference to the NotifyDelegator constructor is passed as an argument to the remote listener. In this case, the HelloWorld class implements RemoteEventListener, implementing a notify method: public void notify(RemoteEvent theEvent) throws UnknownEventException, RemoteException { String mes = "nGot event:" + " Event Id: " + theEvent.getID() + " Event Sequence Number: " + theEvent.getSequenceNumber(); try { // since we are using NotifyDelegator, we can obtain the entry that // triggered the event EntryArrivedRemoteEvent arrivedRemoteEvent = (EntryArrivedRemoteEvent) theEvent; Message msg = (Message) arrivedRemoteEvent.getEntry(); mes = mes + " Message Content: " + msg.content; int notifyType = arrivedRemoteEvent.getNotifyType(); System.out.println(getTime() + mes + " - Notify Type:" + notifyType); } catch (Exception ex) { ex.printStackTrace(); } } The RemoteEvent object passed to the notify method contains the following fields:
The Event Source, Event ID, and Event Sequence Number can be compared to their counterparts in the EventRegistration object that is returned by the NotifyDelegator.getEventRegistration method. The RemoteEvent parameter passed to the notify callback operation can be used to retrieve the Entry that triggered the notify operation using the EntryArrivedRemoteEvent.getEntry() method. More in this SectionGigaSpaces supports two types of notifications: |
Wiki Content Tree
Your Feedback Needed!
We need your help to improve this wiki site. If you have any suggestions or corrections, write to us at techw@gigaspaces.com. Please provide a link to the wiki page you are referring to.
Add Comment