Notifications

Some of the sSpace operations can generate notifications when they are executed. Notifications are also generated when working in clustered mode (schema) that includes a primary/backup schema. A listener can be defined to receive these notifications.

The following SpaceClosed operations may trigger notifications:

  • write(), writeMultiple()

  • asyncTake(), take(), takeById(), takeByIds(), takeIfExists(), takeIfExistsById(), takeMultiple(), clear()

  • AsyncChange, change()

Space operations under transactions will trigger notifications when the transaction commits.

Notify Example

In the following example we register a listener to receive notifications when an Employee instance is written or update in the Space. The client registering the listener will receive a copy of the object written in the Space as notification. The object in the Space will continue to exist.

@EventDriven @Notify @NotifyType(write = true, update = true) @TransactionalEvent public class EmployeeListener { @EventTemplate Employee unprocessedData() { Employee template = new Employee(); template.setStatus("new"); return template; } @SpaceDataEvent public Employee eventListener(Employee event) { // process Employee System.out.println("Notifier Received an Employee"); return null; } } // Register the listener SimpleNotifyEventListenerContainer eventListener = new SimpleNotifyContainerConfigurer( space).eventListenerAnnotation(new EmployeeListener()) .notifyContainer(); eventListener.start(); //....... eventListener.destroy();

For more information, see the Notify Container page.

Polling Example

This example works just like the notification example above, except that the object is removed from the Space:

@EventDriven @Polling @NotifyType(write = true, update = true) @TransactionalEvent public class EmployeeListener { @EventTemplate Employee unprocessedData() { Employee template = new Employee(); template.setStatus("new"); return template; } @SpaceDataEvent public Employee eventListener(Empoyee event) { // process Employee System.out.println("Notifier Received an Employee"); return null; } } // Register the listener SimplePollingEventListenerContainer pollingListener = new SimplePollingContainerConfigurer( space).template(new Employee()) .eventListenerAnnotation(new Object() { @SpaceDataEvent public void eventHappened(Object event) { System.out.println("onEvent called Got" + event); } }).pollingContainer(); pollingListener.start(); //....... pollingListener.destroy();

Fore more information, see the Polling Container page.

Detecting the Current Space Status

Co-Located Applications

When working in clustered mode (schema) that includes a primary/backup schema, several components within the Processing UnitClosed need to be aware of the current Space mode and status, along with any changes that are made to it (such as event containers). A bean that is located in a stateful Processing Unit can use the SpaceStatus listener to be notified about any changes in Space mode or status. This API sends an event any time there is a change in the state of the Space.

The listener sends an event contains the following information about the SpaceMode and SuspendType.

State Description
SpaceMode
Primary The Space mode has changed to Primary.
Backup The Space mode has changed to Backup.
None The Space is currently being initialized, and is not yet in a mode.
SuspendType
None The Space is up and running normally.
Quiesced The Space is in maintenance mode. Operations are blocked until this Space becomes active within the timeout period, and operations can again be performed.
Demoting The Space was formerly in Primary mode, and is being demoted to Backup mode. Operations are blocked until the primary Space becomes active within the timeout period, and operations can again be performed.
Disconnected The Space is not available due to a connection issue.

To enable the SpaceStatus listener, add the following to the puClosed.xml file.

<os-core:annotation-support/>

Adding A Listener by Annotation

To add a listener by annotation, you need to create a Spring bean with a method that receives only one parameter of type SpaceStatusChangedEvent.

Example:

import com.gigaspaces.server.space.suspend.SuspendType; import com.gigaspaces.cluster.activeelection.SpaceMode; import org.openspaces.core.space.status.SpaceStatusChangedEvent; import org.openspaces.core.space.status.SpaceStatusChanged; public class MyListenerByAnnotation { @SpaceStatusChanged public void myMethod(SpaceStatusChangedEvent event) { // Fetch and handle suspend type from event SuspendType suspendType = event.getSuspendType(); handleSuspendType(suspendType); // Fetch and handle space mode from event spaceMode = event.getSpaceMode(); handleSpaceMode(spaceMode); } }

Adding a Listener by Interface

To add a listener by interface, you need to create a bean that implements the interface SpaceStatusChangedListenerByInterface.

Example:

import com.gigaspaces.server.space.suspend.SuspendType; import com.gigaspaces.cluster.activeelection.SpaceMode; import org.openspaces.core.space.status.SpaceStatusChangedEvent; import org.openspaces.core.space.status.SpaceStatusChangedEventListener; public class MyListenerByInterface implements SpaceStatusChangedEventListener { @Override public void onSuspendTypeChanged(SpaceStatusChangedEvent event) { // Fetch and handle suspend type from event SuspendType suspendType = event.getSuspendType(); handleSuspendType(suspendType); // Fetch and handle space mode from event SpaceMode spaceMode = event.getSpaceMode(); handleSpaceMode(spaceMode); } }

Using @PostPrimary for Primary/Backup Notifications

The SpaceStatus listener described above, which was introduced in version 14.0.1, provides expanded functionality and is the preferred method for detecting Space status changes. @PostPrimary is still supported but will be deprecated in a future version.

Using Spring support for application events, two events are defined within OpenSpaces: BeforeSpaceModeChangeEvent and AfterSpaceModeChangeEvent. Both are raised when a Space changes its mode, for example from primary to backup or vice versa, and holds the current Space mode.

Custom beans that need to be aware of the Space mode (for example, working directly against a cluster member, i.e. not using a clustered proxy of the Space, and performing operations against the Space only when it is in primary mode) can implement the Spring ApplicationListener and check for the mentioned events.

OpenSpaces also provides the Space Mode Context Loader, which can load the Spring application context when it has become primary, and unload it when it moves to backup.

In embedded mode, the space factory bean registers with the space for space mode changes. The registration is performed on the actual space instance (and not a clustered proxy of it), and any events raised are translated to the equivalent OpenSpaces space mode change events. In remote mode, a single primary event is raised.

Space mode registration can be overridden and explicitly set within the space factory configuration. Here is an example of how it can be set (it cannot register for notifications even though it is an embedded space):

<os-core:embedded-space id="space" space-name="space" register-for-space-mode-notifications="false" />

A bean can implement the following interfaces to get notified about Space mode changes:

Interface Implemented Method When Invoked
SpaceBeforeBackupListener void onBeforeBackup(BeforeSpaceModeChangeEvent event) Before a space becomes backup
SpaceBeforePrimaryListener void onBeforePrimary(BeforeSpaceModeChangeEvent event) Before a space becomes primary
SpaceAfterBackupListener void onAfterBackup(AfterSpaceModeChangeEvent event) After a space becomes backup
SpaceAfterPrimaryListener void onAfterPrimary(AfterSpaceModeChangeEvent event) After a space becomes primary
class MyBean implements SpaceBeforeBackupListener, SpaceAfterPrimaryListener { // invoked before a space becomes backup public void onBeforeBackup(BeforeSpaceModeChangeEvent event) { // Do something } // invoked after a space becomes primary public void onAfterPrimary(AfterSpaceModeChangeEvent event) { // Do something } }

If the bean does not implement any of the interfaces above, another option is to annotate the bean's methods that need to be invoked when a Space mode changes.

Annotation Method Parameter When Invoked
@PreBackup none or BeforeSpaceModeChangeEvent Before a space becomes backup
@PrePrimary none or BeforeSpaceModeChangeEvent Before a space becomes primary
@PostBackup none or AfterSpaceModeChangeEvent After a space becomes backup
@PostPrimary none or AfterSpaceModeChangeEvent After a space becomes primary
class MyBean { // invoked before a space becomes backup; gets the BeforeSpaceModeChangeEvent as a parameter @PreBackup public void myBeforeBackupMethod(BeforeSpaceModeChangeEvent event) { // Do something } // invoked after a space becomes primary; doesn't get any parameter. @PostPrimary public void myAfterPrimaryMethod() { // Do something } }

In order to enable this feature, the following should be placed within the application context configuration:

<os-core:annotation-support />

When there is more than one Proxy (e.g: embedded, remote, ...), the following should be done in order to be sure that the Primary/ Backup Notifications arrived from the current Space instance:

class MyBean { @Resource(name="gigaSpace") private GigaSpace gigaSpace; @Resource(name="gigaSpace2") private GigaSpace gigaSpace2; boolean isPrimary; @PostPrimary public void afterChangeModeToPrimary(AfterSpaceModeChangeEvent event) { if (SpaceUtils.isSameSpace(gigaSpace.getSpace(), event.getSpace())) isPrimary = true; } @PostBackup public void afterChangeModeToBackup(AfterSpaceModeChangeEvent event) { if (SpaceUtils.isSameSpace(gigaSpace.getSpace(), event.getSpace())) isPrimary = false; } }

The method compareAndSet() allows you to compare the current value of the AtomicBoolean to an expected value. If the current value is equal to the expected value, a new value can be set on the AtomicBoolean. The compareAndSet() method is atomic, so only a single thread can execute it at the same time. Thus, the compareAndSet() method can be used to implement a simple synchronization like lock.

class MyBean { @Resource(name="gigaSpace") private GigaSpace gigaSpace; @Resource(name="gigaSpace2") private GigaSpace gigaSpace2; static AtomicBoolean isPostPrimaryCalled = new AtomicBoolean(false); @PostPrimary public void afterChangeModeToPrimary(AfterSpaceModeChangeEvent event) { if (isPostPrimaryCalled.compareAndSet(false, true) { initialize(); } } @PostBackup public void afterChangeModeToBackup(AfterSpaceModeChangeEvent event) { if (SpaceUtils.isSameSpace(gigaSpace.getSpace(), event.getSpace())) isPrimary = false; } }

Remote Clients

When a remote client is interested to receive events when a Space instance changing its runtime mode (from primary to backup or vice versa), it should implement the SpaceModeChangedEventListener.

For example, see the following example about registering for the event using the Administration API:

Admin admin = new AdminFactory().createAdmin(); Space space = admin.getSpaces().waitFor(spaceName, 10, TimeUnit.SECONDS); SpaceModeChangedEventManager modeManager = space.getSpaceModeChanged(); MySpaceModeListener spaceModeListener = new MySpaceModeListener (space); modeManager.add(spaceModeListener);

The MySpaceModeListener should implement the SpaceModeChangedEventListener - see the following example:

public class MySpaceModeListener implements SpaceModeChangedEventListener{ Space space ; public MySpaceModeListener (Space space) { this.space=space; } public void spaceModeChanged(SpaceModeChangedEvent event) { String partition_member = event.getSpaceInstance().getInstanceId()+""; if (event.getSpaceInstance().getBackupId() != 0) { partition_member = partition_member+ "_" + event.getSpaceInstance().getBackupId(); } System.out.println("SpaceModeChangedEvent: Space " + space.getName() +" - Instance " + partition_member + " moved into " + event.getNewMode()); } }