Summary: The JavaSpaces API is abstracted in OpenSpaces by a simple wrapper: the GigaSpace interface.

Overview

OpenSpaces provides a simpler space API using the GigaSpace interface, by wrapping the IJSpace (and the Jini JavaSpace), and simplifying both the API and its programming model.

The interface allows the POJO domain model to be stored in the space (using GigaSpaces POJO support), declarative transactions, usage of Java 5 Generics, coherent runtime exception hierarchy, and more.

Here is a very simple example of how to define it:

Namespace
<os-core:space id="space" url="/./space" />

<os-core:giga-space id="gigaSpace" space="space"/>

Plain XML
<bean id="space" class="org.openspaces.core.space.UrlSpaceFactoryBean">
    <property name="url" value="/./space" />
</bean>

<bean id="gigaSpace" class="org.openspaces.core.GigaSpaceFactoryBean">
	<property name="space" ref="space" />
</bean>

Code
IJSpace space = // get Space either by injection or code creation

GigaSpace gigaSpace = new GigaSpaceConfigurer(space).gigaSpace();

The GigaSpace interface is a thin wrapper built on top of IJSpace. Within a single Processing Unit (or Spring application context), several GigaSpace instances can be defined, each with different characteristics.

The IJSpace interface is not hidden, and can be used even when using the GigaSpace interface. GigaSpace simplifies most operations used with the space (compared to IJSpace), but some operations still require access to IJSpace, which can be accessed through the GigaSpace API.

  • The GigaSpace variable represents a remote or embedded space proxy (for a single space or clustered) and should be constructed only once throughout the lifetime of the application process.
  • You should treat the GigaSpace variable as a singleton to be shared across multiple different threads.
  • The GigaSpace interface is a thread safe and there is no need to create a GigaSpace variable per application thread.
  • In case the space has been fully terminated (no backup or primary instances running any more) the client space proxy will try to reconnect to the space up to a predefined timeout based on the Proxy Connectivity settings. If it fails to reconnect, an error will be displayed.

Operations

The GigaSpace interface includes the following main operations:

Id Based operations Batch operations Asynchronous operations Data Count operations
readById
takeById
readByIds
takeByIds
readIfExistsById
takeIfExistsById
readMultiple
takeMultiple
writeMultiple
readByIds
takeByIds
asyncRead
asyncTake
execute
count
Data Query operations Data Insert and Update operations Business logic execution operations Data removal operations
read
readMultiple
iterator
write
writeMultiple
execute
executorBuilder
clean
clear
take
takeMultiple

Code Snippets

Space operations with POJO objects can be conducted using the org.openspaces.core.GigaSpace interface or the com.j_spaces.core.IJSpace interface.

The code snippets below use the org.openspaces.core.GigaSpace interface that is the recommended interface.

Write and Read

Write and Read

Getting Space proxy:

UrlSpaceConfigurer urlSpaceConfigurer = new UrlSpaceConfigurer("jini://*/*/mySpace");
GigaSpace space = new GigaSpaceConfigurer(urlSpaceConfigurer.space())
	.defaultTakeTimeout(1000)
 	.defaultReadTimeout(1000)
 	.gigaSpace();

The following writes an Employee object and reads it back using a simple template:

GigaSpace space;
Employee employee = new Employee("Last Name", new Integer(32));
employee.setFirstName("first name");
LeaseContext<Employee> lc = space.write(employee);
Employee template = new Employee();
Employee result = space.read(template);

Notification Registration

Notification Registration

The following registers for notifications:

GigaSpace space;
SimpleNotifyEventListenerContainer
	notifyEventListenerContainer = new SimpleNotifyContainerConfigurer(space)
	.template(new Employee())
	.eventListenerAnnotation(new Object()
		{
		@SpaceDataEvent
		public void eventHappened(Object event) {
		System.out.println("onEvent called Got" + event);
	   	}
	})
	.fifo(true)
	.notifyWrite(true)
	.notifyUpdate(true)
	.notifyContainer();

Batch Write

Batch Write

When writing a batch of objects into the space, these should be placed into an array to be used by the GigaSpace.writeMultiple operation. The returned array will include the corresponding LeaseContext object.

GigaSpace space; 
Employee emps[] = new Employee[2]; 
emps[0] = new Employee("Last Name A", new Integer(10)); 
emps[1] = new Employee("Last Name B", new Integer(20)); 
try { 
    LeaseContext[] leaseContexts = space.writeMultiple(emps); 
    for (int i = 0;i<leaseContexts.length ; i++) { 
        System.out.println ("Object UID " + leaseContexts[i].getUID() + " inserted into the space"); 
    } 
} catch (WriteMultipleException e) { 
    IWriteResult[] writeResult = e.getResults(); 
    for (int i = 0;i< writeResult.length ; i++) { 
        System.out.println ("Problem with Object UID " + writeResult "); 
    } 
}

Batch Read

Batch Read

The following queries the space using SQL:

GigaSpace space;
String querystr	= "age>40";
SQLQuery query = new SQLQuery(Employee.class, querystr);
Employee results[] = space.readMultiple(query , Integer.MAX_VALUE);
Constructing SQLQuery objects is a relatively expensive operation. You should not construct these with every space query operation. Instead, it is recommended to construct it once, and then use it with dynamic query options: SQLQuery.setParameters and SQLQuery.setParameter.

Clear

Clear Objects

You can use the SQLQuery with the GigaSpace.clear to remove objects from the space:

GigaSpace space;
String querystr	= "age>30";
SQLQuery query = new SQLQuery(Employee.class, querystr);
space.clear(query);
When using the SQLQuery with bigger/less than queries, turn on the extended indexing.

Updating an Object

Updating an Object

The GigaSpace.write with the WriteModifiers.UPDATE_ONLY modifier should be used to explicitly perform an update operation. The WriteModifiers.UPDATE_OR_WRITE is the default mode with write operations. This means that subsequent calls to the write operation with an object with identical SpaceId will result in an update operation - i.e. a new object will not be inserted into the space.

Make sure your Space Class will have the SpaceId(autoGenerate=false) when performing update operations.

The GigaSpace.write has a few activity modes - With each mode the return object options are different.:

  1. Inserting or updating an existing object - The WriteModifiers.UPDATE_OR_WRITE modifier should be used. This is the default mode.
  2. Inserting a new object into the space - The WriteModifiers.WRITE_ONLY modifier should be used.
  3. Updating an existing object - The WriteModifiers.UPDATE_ONLY modifier should be used.
  4. Updating an existing object but sending only the modified fields to the space - The WriteModifiers.PARTIAL_UPDATE modifier should be used.
  • when the WriteModifiers.UPDATE_OR_WRITE modifier is applied, the following returns:
    • For a successful operation:
      • LeaseContext - The LeaseContext.getObject() will return:
        • null - if a new object is inserted (write operation)
        • The previous version of the object (update operation)
    • For an unsuccessful operation:
  • when the WriteModifiers.UPDATE_ONLY modifier is applied the following returns:
    • For a successful operation:
      • LeaseContext - Where the LeaseContext.getObject() will return the previous version of the object.
    • For an unsuccessful operation
      • null - if a timeout occurred. This means the object is locked under another transaction.
      • an Exception object is thrown - the options are:
        • EntryNotInSpaceException

          - in case the object does not exist in the space.

        • SpaceOptimisticLockingFailureException

          . Thrown only when running in Optimistic Locking mode. This Exception includes the existing version id of the object within the space and the client side version id of the object. In this case you should read the object again and retry the update operation. See Optimistic Locking for more details.

  • when the WriteModifiers.PARTIAL_UPDATE modifier is applied the return values are the same as with the WriteModifiers.UPDATE_ONLY case. Fields that should not be updated should have the value null. This means that only fields which are set will be sent into the space to replace the existing field's value. Make sure the updated object include its ID when using this option.

When updating an object, you can specify 0 (ZERO) as the lease time. This will instruct the space to use the original lease time used when the object has been written into the space.

UPDATE_OR_WRITE Example:

try
{
	LeaseContext ret = space.write(employee ,/*lease*/  0 ,/*timeout*/  1000 , WriteModifiers.UPDATE_OR_WRITE);
	if ( ret.getObject() == null)
	{
		//  successful write
	}
	if (ret.getObject() instanceof Employee)
	{
		//  successful update
	}
}
catch (UpdateOperationTimeoutException uote)
{
	// Object is locked - unsuccessful update
}

WRITE_ONLY Example:

try
{
	LeaseContext ret = space.write(employee ,/*lease*/  0 ,/*timeout*/  1000 , WriteModifiers.WRITE_ONLY);
	if ( ret.getObject() == null)
	{
		//  successful write
	}
}
catch (EntryAlreadyInSpaceException eainse)
{
	// Object already exists - unsuccessful write
}

UPDATE_ONLY Example:

try
{
	LeaseContext ret = space.write(employee ,/*lease*/  0 ,/*timeout*/  1000 , WriteModifiers.UPDATE_ONLY);
	if ( ret == null)
	{
		// Object is locked - unsuccessful update
	}
	else if (ret.getObject() instanceof Employee)
	{
		//  successful update
	}
}
catch (EntryNotInSpaceException enise)
{
	// Object not in space - unsuccessful update
}
catch (SpaceOptimisticLockingFailureException solfe)
{
	// Client holds wrong version of the object - unsuccessful update. We need to read it again and issue the update call again.
}

PARTIAL_UPDATE Example:

GigaSpace space = new GigaSpaceConfigurer (new UrlSpaceConfigurer("jini://*/*/mySpace").noWriteLease(true)).gigaSpace();

// initial insert
MyClass obj = new MyClass();
obj.setId("1");
obj.setField1("A");
obj.setField2("B");
obj.setField3("C");                               
space.write(obj);

// reading object back from the space
MyClass obj2 = space.readById(MyClass.class , "1");

// updating only field2 
obj2.setField1(null);
obj2.setField2("BBBB");
obj2.setField3(null);
try
{
	space.write(obj2,0,0,WriteModifiers.PARTIAL_UPDATE);
}
catch (EntryNotInSpaceException enise)
{
	// Object not in space - unsuccessful update
}

Batch Update

Batch Update

Make sure your Space Class will have the SpaceId(autoGenerate=false) when performing update operations.

The GigaSpace.updateMultiple returns an array of objects which correspond to the input object array. The returned object element can be one of the following:

  • when the WriteModifiers.UPDATE_OR_WRITE modifier is applied the following returns:
    • For a successful operation:
      • null - if a new object is inserted (write operation)
      • The previous version of the object (update operation)
        Since the GigaSpace.updateMultiple in WriteModifiers.UPDATE_OR_WRITE

        mode does not support timeout based updates, there is no way to identify if an updated object is already locked under a transaction - i.e. the
        UpdateOperationTimeoutException is not returned as part of the returned array elements.
        With a transactional system, it is recommended to perform batch updates using the WriteModifiers.UPDATE_ONLY
        modifier.

        UPDATE_ONLY Example:

        GigaSpace space;
        Employee employees[] = space.readMultiple(query , 10000);
        	Object retUpdateMulti[] = space.updateMultiple(employees ,/*leases*/ new long[results.length],WriteModifiers.UPDATE_ONLY);
        
        for (int i = 0;i<retUpdateMulti ; i++)
        {
        	if  (retUpdateMulti[i] == null ) {
        		//  unsuccessful update
        		break;
        	}
        	else if  (retUpdateMulti[i] instanceof Exception) {
        		//  unsuccessful update
        		if (retUpdateMulti[i] instanceof EntryNotInSpaceException)
        		{
        		...
        		}
        
        		else if (retUpdateMulti[i] instanceof SpaceOptimisticLockingFailureException)
        		{
        		...
        		}
        
        
        		break;
        	}
        
        	else if  (retUpdateMulti[i] instanceof Employee ) {
        		//  successful update
        	}
        }

        PARTIAL_UPDATE Example:

        GigaSpace space;
        for (int i=0;i<employees.length;i++)
        {
        	employees[i].setFirstName(null);
        	employees[i].setLastName(null);
        	employees[i].setBalance(newValue);
        	leases[i] = Lease.FOREVER;
        }
        
        space.writeMultiple(employees, Lease.FOREVER, WriteModifiers.PARTIAL_UPDATE);
The clear and clean operations does not remove the space class definition from the space. You should restart the space to allow it to drop the class definitions.

Clustered Flag

When configuring a Space an IJSpace instance is registered with Spring application context. When starting an embedded space with a cluster topology, or when looking up a remote space started with a cluster topology, a clustered proxy is returned. A clustered proxy is a smart proxy that performs operations against the whole cluster.

Many times, especially when working with a Processing Unit that starts an embedded space, operations against the space should be performed directly on the cluster member. This is a core concept of SBA and Processing Unit, where most if not all operations should be performed in-memory without leaving the processing unit boundaries when a Processing Unit starts an embedded space.

The decision of working directly with a cluster member or against the whole cluster is done in the GigaSpace level. The GigaSpacesFactoryBean provides a clustered flag with the following logic as the default value: If the space is started in embedded mode (for example, /./space), the clustered flag is set to false. When the space is looked up in a remote protocol (Jini or RMI), the clustered flag is set to true. Naturally, the flag can be set explicitly. Here is an example of how the clustered flag can be configured:

Namespace
<os-core:space id="space" url="/./space" />

<!-- By default, since we are starting in embedded mode, clustered=false -->
<os-core:giga-space id="directGigaSpace" space="space"/>

<os-core:giga-space id="clusteredGigaSpace" space="space" clustered="true"/>

Plain
<bean id="space" class="org.openspaces.core.space.UrlSpaceFactoryBean">
    <property name="url" value="/./space" />
</bean>

<!-- By default, since we are starting in embedded mode, clustered=false -->
<bean id="directGigaSpace" class="org.openspaces.core.GigaSpaceFactoryBean">
	<property name="space" ref="space" />
</bean>

<bean id="clusteredGigaSpace" class="org.openspaces.core.GigaSpaceFactoryBean">
	<property name="space" ref="space" />
	<property name="clustered" value="true" />
</bean>

Code
IJSpace space = // get Space either by injection or code creation

GigaSpace gigaSpace = new GigaSpaceConfigurer(space).clustered(true).gigaSpace();

The above example shows a typical scenario where the clustered flag is used. Within a Processing Unit, an application might need to access both the cluster member and the whole cluster directly.

Simpler API

The GigaSpace interface provides a simpler space API by utilizing Java 5 generics, and allowing sensible defaults. Here is an example of the space take operation as defined within GigaSpace:

public interface GigaSpace {

    // ....
    
    <T> T take(T template) throws DataAccessException;
    
    <T> T take(T template, long timeout) throws DataAccessException;
}

In the example above, the take operation can be performed without specifying a timeout. The default take timeout is 0 (no wait), and can be overridden when configuring the GigaSpace factory. In a similar manner, the read timeout and write lease can be specified.

Namespace
<os-core:space id="space" url="/./space" />

<os-core:giga-space id="gigaSpace" space="space" default-take-timeout="1000"/>

Plain XML
<bean id="space" class="org.openspaces.core.space.UrlSpaceFactoryBean">
    <property name="url" value="/./space" />
</bean>

<bean id="gigaSpace" class="org.openspaces.core.GigaSpaceFactoryBean">
	<property name="space" ref="space" />
    <property name="defaultTakeTimeout" value="1000" />
</bean>

Code
IJSpace space = // get Space either by injection or code creation

GigaSpace gigaSpace = new GigaSpaceConfigurer(space).defaultTakeTimeout(1000).gigaSpace();
See more examples for the GigaSpace interface usage with the POJO Support section.

write Operation

A write operation places a copy of an object into the space. The object passed to the write is not affected by the operation. Each write operation places a new object into the space unless there is an object with the same ID already stored within the space. In such a case an update operation will be performed implictly. If you would like to change this default behavior you should change the update mode to use the WriteModifiers.WRITE_ONLY mode. When updating an object with many fields you may use the PARTIAL_UPDATE mode.

When performing a write operation you may provide a lease (time to live) duration (in milliseconds time unit) for the object. The write invocation returns a Lease object allowing you to cancel or renew the object lease. When the lease expires, the object is removed from the space. The default lease duration is FOREVER. An IllegalArgumentException will be thrown if the lease time requested is negative.

If a write returns without throwing an exception, that object is committed to the space, possibly within a transaction. If a RemoteException is thrown, the write may or may not have been successful. If any other exception is thrown, the object was not written into the space.

Writing an object into a space might generate notifications to registered objects.

Return Previous Value

When updating an object which already exists in the space, in some scenarios it is useful to get the previous value of the object (before the update). This previous value is returned in result LeaseContext.getObject() when using the RETURN_PREV_ON_UPDATE modifier.

Since in most scenarios the previous value is irrelevant, the default behavior is not to return it (i.e. LeaseContext.getObject() return null). The RETURN_PREV_ON_UPDATE modifier is used to indicate the previous value should be returned.

Delta Update

You may update selected space object fields (delta) using the WriteModifiers.PARTIAL_UPDATE modifier. This option is useful when having objects with large number of fields where you would like to update only few of the space object fields. This optimizes the network utilization and avoids serializing/de-serializing the entire object fields when interacting with a remote space.

How to Perform Delta Updates?

When using this modifier, fields that you do not want be update should have the value null. This means that only fields which are set will be sent from the client into the space to replace the existing field's value. In case of a backup (replica) space, the primary space will replicate only the updated fields (delta) to the replica space. Make sure the updated object include its ID when using this option.

To use Delta updates you don't have to implement any special interface or have special serialization code. You can use regular POJO as usual.

When updating an object, you can specify 0 (ZERO) as the lease time. This will instruct the space to use the original lease time used when the object has been written into the space.

PARTIAL_UPDATE Example:

GigaSpace space = new GigaSpaceConfigurer (new UrlSpaceConfigurer("jini://*/*/mySpace").noWriteLease(true)).gigaSpace();

// initial insert
MyClass obj = new MyClass();
obj.setId("1");
obj.setField1("A");
obj.setField2("B");
obj.setField3("C");                               
space.write(obj);

// reading object back from the space
MyClass obj2 = space.readById(MyClass.class , "1");

// updating only field2 
obj2.setField1(null);
obj2.setField2("BBBB");
obj2.setField3(null);
try
{
	space.write(obj2,0,0,WriteModifiers.PARTIAL_UPDATE);
}
catch (EntryNotInSpaceException enise)
{
	// Object not in space - unsuccessful update
}

Data Access

There are various mechanisms offered by GigaSpaces XAP to access the data within the space:

ID Based

Each space object includes an ID. You may read or remove objects from the space using their ID via the readByID,takeByID,readIfExistsById,takeIfExistsById, readByIDs or the takeByIDs operations.

The readByID and readByIDs have a special performance optimization when running a Local Cache or Local View.

See the Id Queries for details.

Template Based

The template is a POJO of the desired entry type, and the properties which are set on the template (i.e. not null) are matched against the respective properties of entries of the same type in the space. Properties with null values are ignored (not matched).

See the Template Matching for details.

SQL Based

The SQLQuery class is used to query the space using SQL-like syntax. The query statement includes only the WHERE statement part - the selection aspect of a SQL statement is embedded in other parameters for a SQL query.

See the SQLQuery for details.

Space Iterator

The IteratorBuilder with the GSIterator allows you to iterate over large amount of space objects in a paging approach. It avoids the need to retrieve the entire result set in one batch as the readMultiple since it is fetching the result set in batches. This optimizes the resource utilization (memory and CPU) involved when executing the query both at the client and server side.

See the Paging Support with Space Iterator for details.

readIfExists and read Operations

The two forms of the read operations query the space for an object that matches the template/SQLQuery provided. If a match is found, a copy of the matching object is returned. If no match is found, null is returned. Passing a null reference as the template will match any object.

Any matching object can be returned. Successive read requests with the same template may or may not return equivalent objects, even if no intervening modifications have been made to the space. Each invocation of read may return a new object even if the same object is matched in the space. If you would like to read objects in the same order they have been written into the space you should perform the read objects in a FIFO mode.

A readIfExists operation will return a matching object, or a null if there is currently no matching object in the space. If the only possible matches for the template have conflicting locks from one or more other transactions, the timeout value specifies how long the client is willing to wait for interfering transactions to settle before returning a value. If at the end of that time no value can be returned that would not interfere with transactional state, null is returned. Note that, due to the remote nature of the space, read and readIfExists may throw a RemoteException if the network or server fails prior to the timeout expiration.

A read operation acts like a readIfExists except that it will wait until a matching object is found or until transactions settle, whichever is longer, up to the timeout period.

In both read methods, a timeout of JavaSpace.NO_WAIT means to return immediately, with no waiting, which is equivalent to using a zero timeout. An IllegalArgumentException will be thrown if a negative timeout value is used.

The read operation default timeout is JavaSpace.NO_WAIT.

takeIfExists and take Operations

The take operations perform exactly like the corresponding read operations, except that the matching object is removed from the space on one atomic operation. Two take operations will never return copies of the same object, although if two equivalent objects were in the space the two take operations could return equivalent objects.

If a take returns a non-null value, the object has been removed from the space, possibly within a transaction. This modifies the claims to once-only retrieval: A take is considered to be successful only if all enclosing transactions commit successfully. If a RemoteException is thrown, the take may or may not have been successful. If an UnusableEntryException is thrown, the take removed the unusable object from the space. If any other exception is thrown, the take did not occur, and no object was removed from the space.

With a RemoteException, an object can be removed from a space and yet never returned to the client that performed the take, thus losing the object in between. In circumstances in which this is unacceptable, the take can be wrapped inside a transaction that is committed by the client when it has the requested object in hand.

If you would like to take objects from the space in the same order they have been written into the space you should perform the take objects in a FIFO mode.

Taking an object from the space might generate notifications to registered objects/queries.

The take operation default timeout is JavaSpace.NO_WAIT.

Batch Operations

The GigaSpace interface provides simple way to perform bulk operations. You may read or write large amount of objects in one call. The batch operations can be called using the following:

  • GigaSpace.readMultiple - Bulk read.
  • GigaSpace.takeMultiple - Bulk take (read+remove). Returns the removed objects back to the client.
  • GigaSpace.writeMultiple - Bulk write and update.

To remove batch of objects without returning these back into the client use GigaSpace.clear(SQLQuery);

Here are few important considerations when using the batch operations:

  • The readMultiple and takeMultiple operations boost the performance, since they perform multiple operations using one call. These methods returns the matching results in one result object back to the client. This allows the client and server to utilize the network bandwidth in an efficient manner. In some cases, these batch operations can be up to 10 times faster than multiple single based operations.
  • The readMultiple and takeMultiple operations should be handled with care, since they can return a large data set (potentially all the space data). This might cause an out of memory error in the space and client process. You should use the GSIterator to return the result in batches (paging) in such cases.
  • Destructive batch operations (takeMultiple , writeMultiple , updateMultiple) should be performed with transactions - this allows the client to roll back the space to its initial state prior the operation was started, in case of a failure.
  • When calling writeMultiple or updateMultiple, make sure null values are not part of the passed array.
  • When using writeMultiple, you should verify that duplicated entries (with the same ID) do not appear as part of the passed array, since the identity of the object is determined based on its ID and not based on its reference. This is extremely important with an embedded space, since writeMultiple injects the ID value into the object after the write operation (when autogenerate=false).
  • The readMultiple and takeMultiple operations do not support timeout operations. The simple way to achieve this is by calling the read operation first with the proper timeout, and if non-null values are returned, perform the batch operation.
  • Exception handling - batch operations many throw the following Exceptions. Make sure you catch these and act appropriately:

Asynchronous Operations

The GigaSpace interface supports asynchronous (non-blocking) read and asynchronous take operations through the GigaSpace interface. Both return a Future<T> object, where T is the type of the object the request returns. Future<T>.get() can be used to query the object to see if a result has been returned or not.

Alternatively, asyncRead and asyncTake also accept an implementation of AsyncFutureListener<T>, which will have its onResult(AsyncFuture<T>) method called when the result has been populated. This does not affect the return type of the Future<T>, but provides an additional mechanism for handling the asynchronous response.

Asynchronous write operation can be implemented using a Task, where the Task implementation include a write operation. With this approach the Task is sent to the space and executed in an asynchronous manner. The write operation itself will be completed once both the primary and the backup will acknowledge the operation. This activity will be performed as a background activity from the client perspective.

Space Class
public class MyClass implements Serializable{
	String data;
	Integer id;	
	public MyClass(){}
	public MyClass(int id , String data){
		this.id = id;
		this.data = data;
	}
	public MyClass(int id){this.id = id;}		
	public String getData() {return data;}
	public void setData(String data) {this.data = data;}	
	@SpaceId (autoGenerate = false)
	@SpaceRouting
	public Integer getId() {return id;}
	public void setId(Integer id) {this.id = id;}	
}

AsyncFutureListener
public class AsyncListener implements AsyncFutureListener<MyClass>{
	String operation;
	public AsyncListener(String operation)
	{
		this.operation=operation;
	}
	public void onResult(AsyncResult<MyClass> result) {
		System.out.println("Async " + operation+ 
			" Operation Listener - Found matching object:"+
				result.getResult());
	}
}

Async Read
GigaSpace space = new GigaSpaceConfigurer (new UrlSpaceConfigurer("jini://*/*/space")).gigaSpace();
AsyncFuture<MyClass> futureRead =  space.asyncRead(new MyClass(1), 10000, new AsyncListener("Read"));

Async Take
GigaSpace space = new GigaSpaceConfigurer (new UrlSpaceConfigurer("jini://*/*/space")).gigaSpace();
AsyncFuture<MyClass> futureTake =  space.asyncTake(new MyClass(1), 10000, new AsyncListener("Take"));

Async Write
GigaSpace space = new GigaSpaceConfigurer (new UrlSpaceConfigurer("jini://*/*/space")).gigaSpace();
MyClass obj = new MyClass(1,"AAA");
space.execute(new AsyncWriteTask(obj));
The AsyncWriteTask
public class AsyncWriteTask implements Task<Integer>{
	MyClass obj;
	public AsyncWriteTask (MyClass obj)
	{
		this.obj=obj;
	}
	@TaskGigaSpace
	transient GigaSpace space;
	public Integer execute() throws Exception {
		space.write (obj);
		return 1;
	}
}

Declarative Transactions

As seen in the take API above, there is no need to provide a Jini transaction object for the different space operations. GigaSpace with the different OpenSpaces transaction managers and Spring allow simple declarative definition of transactions. This boils down to the fact that if there is an ongoing transaction running, any operation performed using the GigaSpace interface joins it, using Spring's rich transaction support.

In order to have GigaSpace transactional, the transaction manager must be provided as a reference when constructing the GigaSpace bean. For example (using the distributed transaction manager):

Namespace
<os-core:space id="space" url="/./space" />

<os-core:distributed-tx-manager id="transactionManager"/>

<os-core:giga-space id="gigaSpace" space="space" tx-manager="transactionManager"/>

Plain XML
<bean id="space" class="org.openspaces.core.space.UrlSpaceFactoryBean">
    <property name="url" value="/./space" />
</bean>

<bean id="transactionManager" class="org.openspaces.core.transaction.manager.DistributedJiniTransactionManager">
	<property name="space" ref="space" />
</bean>

<bean id="gigaSpace" class="org.openspaces.core.GigaSpaceFactoryBean">
    <property name="space" ref="space" />
	<property name="transactionManager" ref="transactionManager" />
</bean>

It is highly recommended to read the transaction management chapter in the Spring reference documentation.

Transaction Provider

OpenSpaces provides a pluggable transaction provider using the following interface:

public interface TransactionProvider {

    Transaction getCurrentTransaction(Object transactionalContext, IJSpace space);

    int getCurrentTransactionIsolationLevel(Object transactionalContext);
}

OpenSpaces comes with a default transaction provider implementation, which uses Spring and its transaction manager in order to obtain the currently running transactions and automatically use them under transactional operations.

GigaSpace allows access to the current running transaction using the transaction provider. The following code example shows how the take operation can be performed using IJspace (users normally won't be required to do so):

gigaSpace.getSpace().take(obj, gigaSpace.getCurrentTransaction(), 1000);

Transaction Isolation Level

GigaSpaces supports three isolation levels: READ_UNCOMMITTED, READ_COMMITTED and REPEATABLE_READ (default). When using GigaSpace, the default isolation level that it will perform under can be defined in the following manner:

Namespace
<os-core:space id="space" url="/./space" />

<os-core:giga-space id="gigaSpace" space="space" default-isolation="READ_COMMITTED"/>

Plain XML
<bean id="space" class="org.openspaces.core.space.UrlSpaceFactoryBean">
    <property name="url" value="/./space" />
</bean>

<bean id="gigaSpace" class="org.openspaces.core.GigaSpaceFactoryBean">
	<property name="space" ref="space" />
    <property name="defaultIsolationLevelName" value="READ_COMMITTED" />
</bean>

Code
IJSpace space = // get Space either by injection or code creation

GigaSpace gigaSpace = new GigaSpaceConfigurer(space)
                          .defaultIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED)
                          .gigaSpace();

In addition, Spring allows you to define the isolation level on the transaction definition itself:

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

    private GigaSpace gigaSpace;
    
    public void setGigaSpace(GigaSpace gigaSpace) {
    	this.gigaSpace = gigaSpace;
    }

    public Foo getFoo(String fooName) {
        // do something
    }

    // these settings have precedence for this method
    @Transactional(readOnly = false, 
                   propagation = Propagation.REQUIRES_NEW, 
                   isolation  = Isolation.READ_COMMITTED)
    public void updateFoo(Foo foo) {
        // do something
    }
}

In the above example, any operation performed using GigaSpace in the updateFoo method automatically works under the READ_COMMITTED isolation level.

Exception Hierarchy

OpenSpaces is built on top of the Spring consistent exception hierarchy by translating all of the different JavaSpaces exceptions and GigaSpaces exceptions into runtime exceptions, consistent with the Spring exception hierarchy. All the different exceptions exist in the org.openspaces.core package.

OpenSpaces provides a pluggable exception translator using the following interface:

public interface ExceptionTranslator {

    DataAccessException translate(Throwable e);
}

A default implementation of the exception translator is automatically used, which translates most of the relevant exceptions into either Spring data access exceptions, or concrete OpenSpaces runtime exceptions (in the org.openspaces.core package).

Exception handling for Batch Operations

Batch operations many throw the following Exceptions. Make sure you catch these and act appropriately:

GigaSpaces.com - Legal Notice - 3rd Party Licenses - Site Map - API Docs - Forum - Downloads - Blog - White Papers - Contact Tech Writing - Gen. by Atlassian Confluence