XAP

Document API

Unlike POJOs, which force users to design a fixed data schema (in the form of a class definition) and adhere to it, a Document is much more dynamic - users can add and remove properties at runtime as necessary. A Document always belongs to a certain type, represented by the class SpaceTypeDescriptor.

Before a certain Document instance is written to the Space, its type should be introduced to it. The type has a name and controls metadata such as identifier property, routing property and which properties are initially indexed (naturally, you can also index new properties at runtime after adding them to your Documents).

The Type controls metadata, so only the metadata is part of the type. A Document can introduce new properties at will.

Note that the Document type does not describe the properties themselves (except for the names of the ID and Routing properties). These are completely dynamic and each instance can have a different set of properties, although in most cases Document instances of the same type are likely to have identical or similar set of properties.

Schema Evolution

A SpaceDocument is completely dynamic by nature, so it is very easy to change or evolve your data model without taking down the Space. Simply change your application code to add additional properties or remove existing ones, and you're good to go. Even better, old and new versions can co-exist because the Space doesn't enforce any restrictions regarding the property set of Documents that belong to a certain type. This is a much more lightweight model in comparison to the classic POJO model, where a recompilation and in many cases a full Space restart is required to change the data schema.

If the POJO model can't be replaced with the Document model, yet some level of schema evolution is desired within the POJO model, Dynamic Properties can be used.

Type Definition

Before beginning to write to and read from aSpaceDocument in the Space, an initial schema definition of the document type is needed.

For example, suppose we're implementing an electronic commerce system, and we need a type called Product with the following properties:

Product Property Description
CatalogNumber String
Category String
Name String
Description String
Price Float
Features Nested document (for example: Manufacturer=Acme, RequiresAssembly=false, weight=7.5)
Tags Collection of strings
Reviews Collection of nested documents

The CatalogNumber property is the primary key, partitioning is done according to the Category property, and the Name and Price properties will be indexed because they are used in most of the queries executed.

Remember, the type definition is only for metadata; we're not concerned about fields like Description because they aren't used for indexing or any other metadata.

The following is an example of how to introduce a new Document type:

<os-core:embedded-space id="space" space-name="mySpace"  >
      <os-core:space-type type-name="Product" >
        <os-core:id property="CatalogNumber"/>
        <os-core:routing property="Category"/>
        <os-core:equal-index path="Name"/>
        <os-core:ordered-index path="Price"/>
      </os-core:space-type>
</os-core:embedded-space>
<os-core:giga-space id="gigaSpace" space="space"/>
<bean id="space" class="org.openspaces.core.space.EmbeddedSpaceFactoryBean">
    <property name="name" value="space" />
    <property name="spaceTypes" >
          <list>
        <ref bean="productType"/>
          </list>
     </property>
</bean>
<bean id="gigaSpace" class="org.openspaces.core.GigaSpaceFactoryBean">
    <property name="space" ref="space"/>
</bean>

<bean name="productType"
        class="org.openspaces.core.config.GigaSpaceDocumentTypeDescriptorFactoryBean">
        <property name="typeName" value="Product"/>
        <property name="idProperty">
           <bean class="org.openspaces.core.config.SpaceIdProperty">
             <property name="propertyName" value="CatalogNumber"></property>

           </bean>
        </property>
        <property name="routingProperty">
           <bean class="org.openspaces.core.config.SpaceRoutingProperty">
             <property name="propertyName" value="Category"></property>
           </bean>
        </property>
        <property name="indexes">
             <list>
         <bean class="org.openspaces.core.config.EqualIndex">
                   <property name="path" value="Name"></property>
                 </bean>
                 <bean class="org.openspaces.core.config.OrderedIndex">
                   <property name="path" value="Price"></property>
                 </bean>
          </list>
        </property>
</bean>
public void registerProductType(GigaSpace gigaspace) {
    // Create type descriptor:
    SpaceTypeDescriptor typeDescriptor = new SpaceTypeDescriptorBuilder("Product")
        .idProperty("CatalogNumber")
        .routingProperty("Category")
        .addPropertyIndex("Name", SpaceIndexType.EQUAL)
        .addPropertyIndex("Price", SpaceIndexType.ORDERED)
        .create();
    // Register type:
    gigaspace.getTypeManager().registerTypeDescriptor(typeDescriptor);
}

This code doesn't reflect the complete model, and most of the properties don't need to be introduced to the schema. Only properties with special roles (for example, idProperty and routingProperty) are part of the schema definition. These meta model settings can't be changed without restarting the Space or dropping the type, clearing all its instances, and reintroducing it.

 

Compound SpaceId

Use the following techniques when defining a SpaceId from more than one property.

List<String> idProperties = new ArrayList<>();
idProperties.add("firstName");
idProperties.add("lastName");
SpaceTypeDescriptor typeDescriptor = new SpaceTypeDescriptorBuilder("PersonDoc")
       .addFixedProperty("firstName", String.class)
       .addFixedProperty("lastName", String.class)
       .idProperty(idProperties)
       .create();

gigaSpace.getTypeManager().registerTypeDescriptor(typeDescriptor);

gigSpace.write(new SpaceDocument(typeName)
       .setProperty("firstName", "John")
       .setProperty("lastName", "Smith"));

Space Routing

The routing can be defined using only a single property, for example:

SpaceTypeDescriptorBuilder("PersonDoc")
	.routingProperty("firstName");
	...

IdQuery Matching

Object id = CompoundSpaceId.from("John", "Smith");
gigaSpace.read(new IdQuery<>("PersonDoc", id));
gigaSpace.readById(new IdQuery<>("PersonDoc", id));
gigaSpace.readByIds(new IdQuery<>("PersonDoc", new Object[]{id1, id2};
));

Template Matching

//exact match
SpaceDocument template = new SpaceDocument("PersonDoc")
       .setProperty("firstName", "John")
       .setProperty("lastName", "Smith");

gigaSpace.read(template);

//partial match
SpaceDocument template = new SpaceDocument("PersonDoc")
       .setProperty("firstName", "John");
gigaSpace.read(template);

SQLQuery Matching

//exact matching
SQLQuery<SpaceDocument> query = new SQLQuery<>("PersonDoc", "firstName=? AND lastName=?");
       .setParameter(1, "John"))
       .setParameter(2, "Smith"));
gigaSpace.read(query);

//partial matching
SQLQuery<SpaceDocument> query = new SQLQuery<>("PersonDoc", "firstName=?", "John");
gigaSpace.read(query);

Querying with JDBC

SpaceDocuments don't have fixed schema, so each document can have a different set of properties. If you want to query documents via JDBC (either directly from the code or using tools such as Tableau or Apache Zeppelin), you must supply a schema so that the JDBC connection can infer metadata and execute queries. For example, executing a query like SELECT * FROM Person requires a schema that contains the set of columns.

A schema can be provided in one of the following ways:

  • Space type descriptor (default) - When defining the type descriptor you can define fixed properties, each of which will be included in the schema. However, each time you modify the schema you must restart the entire cluster because JDBC clients load the schema only once during initialization, so they have to be restarted to discover schema changes.

    In order to query idProperty and routingProperty using JDBC or when Tiered Storage is enabled you must also define them as fixed properties, as idProperty is defined in the following example.

    You can use addIdPropertyType() or addRoutingPropertyType() respectively for specifying the property type. When id and routing are the same property, only set addIdPropertyType().

     SpaceTypeDescriptor typeDescriptor = new SpaceTypeDescriptorBuilder("Product")        
    .idProperty("id")
    .addFixedProperty("name", String.class)
    .addFixedProperty("price", Float.class)
    .addFixedProperty("id", String.class).create();

  • External XML file - You can define the schema in an XML file, and configure its location using the jdbc-alt-schema-url Space property. JDBC clients that connect to the Space can check whether this Space property is configured; if it is, the client then reads the schema from the XML file instead of from the Space type descriptor. This enables changing the schema definition during runtime without having to restart the Space. The XML file should be hosted in a location accessible to the clients, such as a web server. The jdbc-alt-schema-url property points to the XML file as one of the following:

    In this example, the property is set to a URL:

    <os-core:space id="space" url="/./sql-test-space-alt?locators=localhost:4174">
        <os-core:properties>
            <props>
                <prop key="jdbc-alt-schema-url">http://my-server/path/to/my-schema.xml</prop>
            </props>
        </os-core:properties>
    </os-core:space>

    In this example, the my-schema.xml file defines the schema.

    <my-schema>
        <table name="Purchase">
            <column name="id" type="java.lang.String"/>
            <column name="name" type="java.lang.String"/>
            <column name="price" type="java.lang.Float"/>
        </table>
    </my-schema>

Creating and Writing Documents

To create a Document, create a Map<String,Object> with the requested properties, create a SpaceDocument object using the type name and properties, and write it to the Space using the regular GigaSpace write method:

public void writeProduct1(GigaSpace gigaspace) {
    // 1. Create the properties:
    Map<String, Object> properties = new HashMap<String, Object>();
    properties.put("CatalogNumber", "hw-1234");
    properties.put("Category", "Hardware");
    properties.put("Name", "Anvil");
    properties.put("Price", 9.99f);
    properties.put("Tags", new String[] {"heavy", "anvil"});

    Map<String, Object> features = new HashMap<String, Object>();
    features.put("Manufacturer", "Acme");
    features.put("RequiresAssembly", false);
    features.put("Weight", 100);
    properties.put("Features", features);

    Map<String, Object> review1 = new HashMap<String, Object>();
    review1.put("Name", "Wile E. Coyote");
    review1.put("Rate", 1);
    review1.put("Comments", "Don't drop this on your toe, it will hurt.");
    Map<String, Object> review2 = new HashMap<String, Object>();
    review2.put("Name", "Road Runner");
    review2.put("Rate", 5);
    review2.put("Comments", "Beep Beep!");
    properties.put("Reviews", new Map[] {review1, review2});

    // 2. Create the document using the type name and properties:
    SpaceDocument document = new SpaceDocument("Product", properties);
    // 3. Write the document to the space:
    gigaspace.write(document);
}

Another way is to use the DocumentProperties class provided, which extends HashMap to provide fluent coding:

public void writeProduct2(GigaSpace gigaspace) {
    // 1. Create the properties:
    DocumentProperties properties = new DocumentProperties()
        .setProperty("CatalogNumber", "av-9876")
        .setProperty("Category", "Aviation")
        .setProperty("Name", "Jet Propelled Pogo Stick")
        .setProperty("Price", 19.99f)
        .setProperty("Tags", new String[] {"New", "Cool", "Pogo", "Jet"})
        .setProperty("Features", new DocumentProperties()
            .setProperty("Manufacturer", "Acme")
            .setProperty("RequiresAssembly", true)
            .setProperty("NumberOfParts", 42))
        .setProperty("Reviews", new DocumentProperties[] {
            new DocumentProperties()
                .setProperty("Name", "Wile E. Coyote")
                .setProperty("Rate", 1),
            new DocumentProperties()
                .setProperty("Name", "Road Runner")
                .setProperty("Rate", 5)});

    // 2. Create the document using the type name and properties:
    SpaceDocument document = new SpaceDocument("Product", properties);
    // 3. Write the document to the space:
    gigaspace.write(document);
}

You can map JSON to and from a SpaceDocument with any parser. Here is an example:

package xap.sandbox.document;

import java.io.IOException;
import java.util.HashMap;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.openspaces.core.GigaSpace;
import org.openspaces.core.GigaSpaceConfigurer;
import org.openspaces.core.space.EmbeddedSpaceConfigurer;

import com.gigaspaces.document.SpaceDocument;
import com.gigaspaces.metadata.SpaceTypeDescriptor;
import com.gigaspaces.metadata.SpaceTypeDescriptorBuilder;
import com.gigaspaces.metadata.index.SpaceIndexType;
import com.j_spaces.core.client.SQLQuery;

public class ConvertJSONTODocument {

    @SuppressWarnings("unchecked")
    public static void main (String[] args) throws JsonGenerationException, JsonMappingException, IOException{
        
        GigaSpace gigaSpace = new GigaSpaceConfigurer(new EmbeddedSpaceConfigurer("mySpace")).gigaSpace();
        
        /****
         * We Need to Register a type by specifying a name, id, and routing field.
         * Routing is used to partition data across the grid, similar to a shard key 
         * This only needs to be done once 
         */
        final String PRODUCT_TYPE_NAME = "Product";

        SpaceTypeDescriptor typeDescriptor = new SpaceTypeDescriptorBuilder(PRODUCT_TYPE_NAME)
                    .idProperty("id")
                    .routingProperty("location")
                    .addPropertyIndex("processed", SpaceIndexType.EQUAL)
                    .create();

        gigaSpace.getTypeManager().registerTypeDescriptor(typeDescriptor);

        /****
         * Example JSON payload containing the properties 
         * of the new Type. In this example we use jaxson object mapper.
         * You can use any parser you would like
         */
        String jsonPayload = "{\"id\":1, \"location\":\"usa\", \"processed\":false}";

        HashMap<String,Object> jsonProperties =
                new ObjectMapper().readValue(jsonPayload, HashMap.class);

        /****
         * Convert to a space document simply pass the hash map to the 
         * in to the SpaceDocument Constructor along with the document type name
         * from above
         */
        SpaceDocument dataAsDocument = new SpaceDocument(PRODUCT_TYPE_NAME, jsonProperties);

        /***
         * Insert to the grid
         */
        gigaSpace.write(dataAsDocument);

        /***
         * To confirm the result. Read the document from the grid
         */
        SpaceDocument dataAsDocumentFromGrid = gigaSpace.read(new SQLQuery<SpaceDocument>(PRODUCT_TYPE_NAME, "id = ?", 1));

        /***
         * Map the Object back to JSON
         */
        String jsonFromGrid = new ObjectMapper().writeValueAsString(dataAsDocumentFromGrid);
        
        System.out.println(jsonFromGrid);
    }
}
  • The GigaSpace.writeMultiple method can be used to write a batch of documents.
  • Update semantics are the same as POJO, except partial update that is not currently supported.
  • Use only alphanumeric characters (a-z, A-Z, 0-9) and the underscore ("_") to construct property keys. Other characters might have special behavior in GigaSpaces (for example, "." is used to distinguish nested paths).

Reading and Removing

There are three types of document queries, described in the following sections.

Template Query

This type of query uses a Space Document with type and any other set of properties values as a template for the query For example: Read a document of type Product whose Name is Anvil:

public SpaceDocument readProductByTemplate(GigaSpace gigaSpace) {
    // Create template:
    SpaceDocument template = new SpaceDocument("Product");
    template.setProperty("Name", "Anvil");
    // Read:
    SpaceDocument result = gigaSpace.read(template);
    return result;
}

SQL Query

You can use the SQLQuery to search for matching SpaceDocument entries. For example: Read a document of type Product whose Price is greater than 15:

public SpaceDocument readProductBySQL(GigaSpace gigaSpace) {
    // Create query:
    SQLQuery<SpaceDocument> query =
        new SQLQuery<SpaceDocument>("Product", "Price > ?");
    query.setParameter(1, 15f);
    // Read:
    SpaceDocument result = gigaSpace.read(query);
    return result;
}

Consider indexing properties used in queries to boost performance.

Queries on nested properties are supported. For example, to read products manufactured by Acme:

public SpaceDocument[] readProductBySQLNested(GigaSpace gigaSpace) {
    // Create query:
    SQLQuery<SpaceDocument> query =
        new SQLQuery<SpaceDocument>("Product", "Features.Manufacturer = ?");
    query.setParameter(1, "Acme");
    // Read:
    SpaceDocument[] result = gigaSpace.readMultiple(query, 10);
    return result;
}

ID-Based Query

This code example shows how to read a document of type Product whose ID is hw-1234:

public SpaceDocument readProductById(GigaSpace gigaSpace) {
    return gigaSpace.readById(new IdQuery<SpaceDocument>("Product", "hw-1234"));
}

Queries by multiple IDs are supported. For example:

public SpaceDocument[] readProductByMultipleIds(GigaSpace gigaSpace) {
    Object[] ids = new Object[] {"hw-1234", "av-9876"};
    ReadByIdsResult<SpaceDocument> result =
        gigaSpace.readByIds(new IdsQuery<SpaceDocument>("Product", ids));
    return result.getResultsArray();
}
  • All other GigaSpace query operations (readIfExists, readMultiple, take, takeIfExists, takeMultiple, count, and clear) are also supported for documents entries.
  • All other ID-based operations (readIfExists, takeById, takeIfExistsById, takeByIds) arealso supported for documents.
  • All overloads of those operations with timeout, transactions, modifiers etc. are supported for documents. The semantics is similar to POJOs.

An ID-based query will not return results if the condition is on an auto-generated ID field _spaceId (generated for spaceDocument). Internal fields should not be queried because implementations are subject to change.

Nested Properties

The Document properties values can be either scalars (integers, strings, enumerations, etc), collections (arrays, lists), or nested properties (Map or an extension of map, such as DocumentProperties). Values must adhere to the same restrictions as in the POJO model (e.g. be serializable). Nested properties can be queried by using the "." notation to describe paths, as shown above.

It is highly recommended to use DocumentProperties for nested documents because it contains performance and memory footprint optimizations that are tailored for GigaSpaces usage.

  • While it is possible to use SpaceDocument as a property, it is probably a mistake, because it contains extra information that is not relevant for nested properties (type name, version, etc.).

  • Changing nested properties in an embedded Space is not safe.

Document Hierarchy

SpaceDocument query supports hierarchical relationships so that entries of a child are visible in the context of the parent document, but not the other way around. For example, a document with name Employee can register its parent document Person in the following way:

SpaceTypeDescriptor employeeDescriptor = new SpaceTypeDescriptorBuilder(
                "Child Document Type Name", parentSpaceTypeDescriptor).create();

Here is an example:

    public static void main(String[] args) {

        // Create the Space
        GigaSpace space = new GigaSpaceConfigurer(new EmbeddedSpaceConfigurer(
                "mySpace")).gigaSpace();

        registerDocument(space);

        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("Id", "1234");
        properties.put("FirstName", "John");
        properties.put("LastName", "Fellner");

        SpaceDocument document1 = new SpaceDocument("Person", properties);

        space.write(document1);

        properties = new HashMap<String, Object>();
        properties.put("Id", "12345");
        properties.put("FirstName", "John");
        properties.put("LastName", "Walters");
        properties.put("employeeId", "1234");

        SpaceDocument document2 = new SpaceDocument("Employee", properties);

        space.write(document2);

        SQLQuery<SpaceDocument> query1 = new SQLQuery<SpaceDocument>(
                "Person", "");

        SpaceDocument[] result = space.readMultiple(query1);

        // You should see two documents
        System.out.println(result.length);

        SQLQuery<SpaceDocument> query2 = new SQLQuery<SpaceDocument>(
                "Employee", "");

        SpaceDocument[] result2 = space.readMultiple(query2);

        // You should see one document
        System.out.println(result2.length);

        System.exit(1);

    }
    static public void registerDocument(GigaSpace space) {
        SpaceTypeDescriptor personDescriptor = new SpaceTypeDescriptorBuilder(
                "Person").idProperty("Id").create();
        // Register type:
        space.getTypeManager().registerTypeDescriptor(personDescriptor);

        SpaceTypeDescriptor employeeDescriptor = new SpaceTypeDescriptorBuilder(
                "Employee", personDescriptor).create();
        // Register type:
        space.getTypeManager().registerTypeDescriptor(employeeDescriptor);
    }

Indexing

Properties and nested paths can be indexed to boost query performance. In the type registration sample above, the Name and Price properties are indexed.

The schema is flexible and new properties may be added after the type has been registered, therefore it is possible to add indexes dynamically as well.

For more information about indexing, see the Indexing page.

Events

Event containers (both polling container and notify container) support Space Document entries.

Here is a simple example of a polling event container configuration using a Document:

<!-- Enable scan for OpenSpaces and Spring components -->
<context:component-scan base-package="com.mycompany"/>

<!-- Enable support for @Polling annotation -->
<os-events:annotation-support />

<os-core:embedded-space id="space" space-name="mySpace">
      <os-core:space-type type-name="Product" >
        <os-core:id property="CatalogNumber"/>
        <os-core:routing property="Category"/>
        <os-core:equal-index path="Name"/>
        <os-core:ordered-index path="Price"/>
      </os-core:space-type>
</os-core:embedded-space>

<os-core:giga-space id="gigaSpace" space="space"/>
@EventDriven @Polling
public class SimpleListener {

    @EventTemplate
    SpaceDocument unprocessedData() {
        SpaceDocument template = new SpaceDocument("Product");
        template.setProperty("Name","Anvil");
        return template;
    }

    @SpaceDataEvent
    public SpaceDocument eventListener(SpaceDocument event) {
        //process Data here
    }
}
<os-core:embedded-space id="space" space-name="mySpace">
  <os-core:space-type type-name="Product" >
        <os-core:id property="CatalogNumber"/>
        <os-core:routing property="Category"/>
        <os-core:equal-index path="Name"/>
        <os-core:ordered-index path="Price"/>
      </os-core:space-type>
</os-core:embedded-space>

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

<bean id="simpleListener" class="SimpleListener" />

<os-events:polling-container id="eventContainer" giga-space="gigaSpace">

    <os-core:template>
         <bean class="com.gigaspaces.document.SpaceDocument">
                <constructor-arg value="Product"/>
                <constructor-arg type="java.util.Map">
                    <map>
                        <entry key="Name" value="Anvil" />
                    </map>
                </constructor-arg>
         </bean>
    </os-core:template>

    <os-events:listener>
        <os-events:annotation-adapter>
            <os-events:delegate ref="simpleListener"/>
        </os-events:annotation-adapter>
    </os-events:listener>
</os-events:polling-container>

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

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

<bean id="simpleListener" class="SimpleListener" />

<bean id="eventContainer"
    class="org.openspaces.events.polling.SimplePollingEventListenerContainer">

    <property name="gigaSpace" ref="gigaSpace" />

    <property name="template">
        <bean class="com.gigaspaces.document.SpaceDocument">
                <constructor-arg value="Product"/>
                <constructor-arg type="java.util.Map">
                    <map>
                        <entry key="Name" value="Anvil" />
                    </map>
                </constructor-arg>
         </bean>
    </property>

    <property name="eventListener">
        <bean class="org.openspaces.events.adapter.AnnotationEventListenerAdapter">
            <property name="delegate" ref="simpleListener" />
        </bean>
    </property>
</bean>

GigaSpace gigaSpace = // either create the GigaSpace or get it by injection

SpaceDocument template = new SpaceDocument("Product");
template.setProperty("Name","Anvil");
SimplePollingEventListenerContainer pollingEventListenerContainer = new SimplePollingContainerConfigurer(gigaSpace)
                .template(template)
                .eventListenerAnnotation(new Object() {
                    @SpaceDataEvent
                    public void eventHappened() {
                        eventCalled.set(true);
                    }
                }).pollingContainer();

// when needed close the polling container
pollingEventListenerContainer.destroy();

FIFO Support

FIFO support is off by default with Document entries (same as with POJO). To enable FIFO support, modify the type introduction code and set the desired FIFO support mode. For example:

<os-core:embedded-space id="space" space-name="mySpace">
    <os-core:space-type type-name="Product" fifo-support="OPERATION" >
        <!-- other properties definition -->
    </os-core:space-type>
</os-core:embedded-space>
<os-core:giga-space id="gigaSpace" space="space"/>
<bean id="space" class="org.openspaces.core.space.EmbeddedSpaceFactoryBean">
    <property name="name" value="space" />
    <property name="spaceTypes" >
          <list>
        <ref bean="productType"/>
          </list>
    </property>
</bean>
<bean id="gigaSpace" class="org.openspaces.core.GigaSpaceFactoryBean">
    <property name="space" ref="space"/>
</bean>

<bean name="productType"
        class="org.openspaces.core.config.GigaSpaceDocumentTypeDescriptorFactoryBean">
        <property name="typeName" value="Product"/>
        <!-- other properties definition -->
        <property name="fifoSupport" value="OPERATION"/>

</bean>
// Create type descriptor:
SpaceTypeDescriptor typeDescriptor = new SpaceTypeDescriptorBuilder("Product")
    // Other type descriptor settings.
    .fifoSupport(FifoSupport.OPERATION)
    .create();
// Register type:
gigaspace.getTypeManager().registerTypeDescriptor(typeDescriptor);

Changing FIFO support after a type has been registered is not supported

For more information about FIFO, see the FIFO Support page.

Transactions and Optimistic Locking

Transactions and isolation modifiers semantics is identical to the POJO semantics. For more information about transactions, see the Transaction Management page.

Optimistic locking is disabled by default with Document entries (same as with POJO). To enable it, modify the type introduction code and set the optimistic locking support. For example:

<os-core:embedded-space id="space" space-name="mySpace">
      <os-core:space-type type-name="Product" optimistic-lock="true" >
        <!-- other properties definition -->
      </os-core:space-type>
</os-core:embedded-space>
<os-core:giga-space id="gigaSpace" space="space"/>
<bean id="space" class="org.openspaces.core.space.EmbeddedSpaceFactoryBean">
    <property name="name" value="space" />
    <property name="spaceTypes" >
          <list>
        <ref bean="productType"/>
          </list>
    </property>
</bean>
<bean id="gigaSpace" class="org.openspaces.core.GigaSpaceFactoryBean">
    <property name="space" ref="space"/>
</bean>

<bean name="productType"
        class="org.openspaces.core.config.GigaSpaceDocumentTypeDescriptorFactoryBean">
        <property name="typeName" value="Product"/>

        <!-- other properties definition -->
        <property name="optimisticLock" value="true"/>
</bean>
// Create type descriptor:
SpaceTypeDescriptor typeDescriptor = new SpaceTypeDescriptorBuilder("Product")
    // Other type descriptor settings.
    .supportsOptimisticLocking(true)
    .create();
// Register type:
gigaspace.getTypeManager().registerTypeDescriptor(typeDescriptor);

Changing optimistic locking after a type has been registered is not supported.

For more information about optimistic locking, see the Optimistic Locking page.

Local Cache / Local View

Local View and Local Cache are supported for Documents. By default, the SpaceDocument instance is stored in the cache which speeds up query performance since the data does not need to be transformed from internal structure to SpaceDocument.

If you intend to use local cache or local view in a mixed POJO-Document environment, please refer to Document-POJO Interoperability.

Persistency

External Data Source is supported for space documents. Example on how to implement an EDS that persists SpaceDocuments of type Trade:

<bean id="documentDataSource" class="com.test.DocumentEDS"/>

<os-core:embedded-space id="space" space-name="mySpace" schema="persistent" external-data-source="documentDataSource">
    <os-core:space-type type-name="Trade" >
       <os-core:id property="uid" auto-generate="true"/>
       <os-core:routing property="symbolLabel"/>
    </os-core:space-type>
    <os-core:properties>
        <props>
            <prop key="space-config.external-data-source.data-class">com.gigaspaces.document.SpaceDocument</prop>
        </props>
    </os-core:properties>
</os-core:embedded-space>
package com.test;

public class DocumentEDS
        implements ManagedDataSource<SpaceDocument>, BulkDataPersister
{

    public void init(Properties prop) throws DataSourceException
    {
        // initialize persistency layer
    }

    public DataIterator<SpaceDocument> initialLoad() throws DataSourceException
    {
        // load all the data from persistency
        // build and return an iterator of documents
    }

    public void executeBulk(List<BulkItem> bulk) throws DataSourceException
    {
        for (BulkItem bulkItem : bulk)
        {
            SpaceDocument document = (SpaceDocument) bulkItem.getItem();

            switch (bulkItem.getOperation())
            {
                case BulkItem.WRITE:

                   // writeDocument(document);
                    break;
                case BulkItem.UPDATE:

                   // updateDocument(document, bulkItem.getIdPropertyName());
                    break;
                case BulkItem.REMOVE:
                    //removeDocument(document, bulkItem.getIdPropertyName());

                    break;

                default:
                    break;
            }
        }
    }

    public void shutdown() throws DataSourceException
    {
        //cleanup resources and close the persistency
    }

}

Different document databases can be used to implement the document persistency, such as MongoDB and CouchDB. POJOs can be persisted via document EDS as well, in the same way.

  • In order to support initialLoad of documents the relevant types must be declared in the Space bean, so that they are registered in the space before initialLoad is invoked.
  • Document persistence is currently not provided by default - If needed, an External Data Source should be implemented to fit the required solution.

Transient Documents

When using a persistent Space, there are situations where not all Space Documents need to be persisted. You can specify a document as transient by invoking the setTransient() method.

   SpaceDocument doc = new SpaceDocument("Entity");
   ......       
   doc.setTransient(true);

Space Filters

Space Filters are supported for Space Documents.

If you intend to use Space filters in a mixed POJO-Document environment, see the Interoperability page.

Replication Filters

Space Replication Filters are supported for Space Documents.

If you intend to use Space replication filters in a mixed POJO-Document environment, see the Interoperability page.