JavaSpaces UID Support

  Search Here
Searching XAP 6.0 Documentation

                                               

Summary: How to access space objects using their unique identifiers (UID).
All the methods described with this topic are relevant only for Java net.jini.core.entry.Entry domain based classes

Overview

GigaSpaces allows space Entries to be accessed using their unique identifiers (UID). This powerful option allows users to access space Entries very quickly without having to use the space matching subsystem.

  • You may pass around UIDs among different network services instead of the Entries themselves, as you would for object references and you can manipulate the Entry using its UID.
  • You can get an array of Entries using the array of their UIDs, or you can get a list of Entry UIDs that match a given template and iterate through these UIDs to read Entries from a space into the client in a much more scalable approach.
  • This multi-level Entry retrieval mechanism provides maximum scalability when a client with limited memory size needs to read a huge amount of entries from the space.
  • You may use your own unique ID generator subsystem to be used as the Entry UID. See the ClientUIDHandler class (com.j_spaces.core.client.ClientUIDHandler; see Javadoc).
  • You may build parent-child patterns allowing "one to many" or "many to one" relationships to be stored as part of the space by holding the parent UID as part of the child object as a string attribute or storing the child objects UID as collection of UID attribute as part of the parent object.

The UID is a string based identifier and is composed of the following parts:

  • Class information – class hashcode and name size.
  • Space node name – At clustered environment combined from container-name :space name. At non-clustered environment combined from a dummy name.
  • Timestamp.
  • Counter.

UID is supported by the Entry API and by the ExternalEntry API.

When generating UIDs, the ClientUIDHandler should be used. For example:
MyEntry entry = new MyEntry();
String uid = ClientUIDHandler.createUIDFromName(myUID, MyEntry.class.getName() );
entry.__setEntryInfo(new EntryInfo(uid, 0);

The user in this case must make sure the myUID is unique!

Defining Custom UID

By default, GigaSpaces generates a unique ID automatically, and you can retrieve it through the lease after calling the write or from an Entry object as described in Using UID with Entry Objects. However, you also have the option of using your own unique name as an Entry UID.

The ClientUIDHandler method allows you to supply your own unique name for an Entry and receive a formatted UID string generated from that name. This allows you to maintain your own object classification while ensuring the uniqueness of IDs. ClientUIDHandler also provides a method that converts UIDs into original names, so that you can identify objects received.

The procedure below explains how to create an Entry with a user-defined UID. Following it is a code sample that illustrates the process.

To create an Entry with a user-defined UID:

  1. Create an Entry. Make sure it implements the entryInfo access methods or extends MetaDataEntry.
  2. Call the method CreateUIDFromName, supplying your unique name for the entry (name) and the name of the class of which the Entry is an instance
    (className). The method returns a UID string. The following characters are not allowed as part of the Entry name: ! @ # $ % ^ & * ( ) _ + = - ? > < , . / " : ; ' | \ } { [ ] ^.
    This UID is not identical to the name you supplied, but it is based on it. You can reconstruct the original name using the method ClientUIDHandler.getNameFromUID.
  3. Construct entryInfo with the UID.
  4. Set the entryInfo to the Entry you created in step 1.
  5. Write the Entry to the space.
    If an Entry with the same UID already exists in the space, EntryAlreadyInSpaceException is thrown.
import net.jini.core.lease.Lease;
 import net.jini.space.JavaSpace;
 import com.j_spaces.core.IJSpace;
 import com.j_spaces.core.LeaseProxy;
 import com.j_spaces.core.client.EntryInfo;
 import com.j_spaces.core.client.SpaceFinder;
 import com.j_spaces.core.client.ClientUIDHandler ;

 public class MyEntry extends com.j_spaces.core.client.MetaDataEntry {

        public String myData;

        public MyEntry() {

        }

        public MyEntry(String data) {

                this.myData = data;
        }

        public String toString()
        {return myData;}
        public static void main(String[] args) {

                try {

                     IJSpace space = (IJSpace) SpaceFinder.find(args[0]);
                     // Setting Entry UID
                     MyEntry myentry = new MyEntry("Data");
                     // make sure you provide unique name!
                     String uid1 = ClientUIDHandler.createUIDFromName("MyEntryUID" ,MyEntry.class.getName() );

                     EntryInfo ei1 = new EntryInfo(uid1 , 0);
                     myentry.__setEntryInfo(ei1);
                     // Write entry to space
                     Lease l = space.write(myentry, null, Lease.FOREVER);
                     LeaseProxy lp =(LeaseProxy)l;
                     System.out.println("Wrote Object with UID:" +    lp.getUID());

                        // Reading Entry using its UID
                        MyEntry template = new MyEntry();

                        String uid2 =
ClientUIDHandler.createUIDFromName(
                           "MyEntryUID" ,MyEntry.class.getName() );
                        EntryInfo ei2 = new EntryInfo(uid2 , 0);
                        template.__setEntryInfo(ei2);
                        MyEntry m = (MyEntry) space.read(
                           template, null, JavaSpace.NO_WAIT);
                        System.out.println("Read Object with UID:" +
                   m.__getEntryInfo().m_UID + " Data:" +m.myData);

                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
 }

Using UID with Entry objects

You can get the Entry's UID from the Entry lease object. See the example below:

Message o = new Message ("A");
Lease lease = space.write(o, null, Lease.FOREVER);
LeaseProxy lp = (LeaseProxy) lease;
String uid = lp.getUID();

In situations where you do not have the Entry lease object (like when using the read operation), you need to get it from the Entry object.

In order to access the Entry's UID from the Entry object, you need to add two methods to the class implementation, with the following signatures:

public void __setEntryUID(String inUid)
public String __getEntryUID()

The example below describes how these methods should be implemented.

package helloworld;
import net.jini.core.entry.entry;
public class Message implements entry
{
    public String content;
    transient public String mUID;
    public Message() {}

    public void __setEntryUID(String inUid)
    {
      this.mUID = inUid;
    }

    public String __getEntryUID()
    {
        return mUID;
    }

    public Message(String content)
    {
        this.content = content;
    }
}

The Entry class should have an attribute that will store the UID.

transient public String mUID;

This attribute's data should not be stored as part of the Entry's attributes in the space, so it should be a transient type.

The __setEntryUID method is called internally by the GigaSpaces when the Entry is materialized at the client side injecting the Entry UID value into the relevant field.

You can access the injected UID using the __getEntryUID method:

Message myobj =(Message) space.read(template, null, JavaSpace.NO_WAIT);
String uid = myobj.__getEntryUID();

The example below reads the Entry using its UID:

Message templateUID = new Message ();
templateUID.__setEntryUID(uid);
//Reading entry using its ID
Message m = (Message) space.read(templateUID,null,JavaSpace.NO_WAIT);
When you do not define the Entry's UID yourself, the UID is injected into the Entry when the Entry is materialized.
When you do define the Entry's UID, you must create it using the ClientUIDHandler.

Reading or Taking Multiple Entries using UIDs

You can read or take multiple Entries from the space using their UIDs, in one space operation.

You should construct an ExternalEntry template that includes only an array of the Entry's UID, and use this template with the readMultiple operation. See the example below:

The Entry Class:

public class MyEntry extends MetaDataEntry{
	public MyEntry (){}
	public MyEntry (int num)
	{
		this.attr1 = "attr1 " + num;
		this.attr2 = "attr2 " + num;
	}
	public String attr1;
	public String attr2;

	public String toString()
	{
		return "UID:"  + __getEntryInfo().m_UID + " attr1:" + attr1 + " attr2:"+ attr2;

	}
}

The Application code:

IJSpace space = (IJSpace )SpaceFinder.find("/./mySpace");
String uid[] = new String[10];
for (int i=0; i<10 ;i++ )
{
	uid[i] = ClientUIDHandler.createUIDFromName(i , MyEntry.class.getName());
	MyEntry entry = new MyEntry(i);
	entry.__setEntryInfo(new EntryInfo(uid[i],0));
	space.write(entry , null ,Lease.FOREVER );
}
ExternalEntry multiUIDtemplate = new ExternalEntry(uid);
Entry[] result = space.readMultiple(multiUIDtemplate , null , Integer.MAX_VALUE);

for (int i=0; i<result.length ;i++ )
{
	ExternalEntry ee = (ExternalEntry)result[i];
	System.out.println(ee.getEntry(space));
}

Lazy Loading

By using the ExternalEntry, you can query the space and get only the UIDs of the matching Entries. In a later phase you may retrieve the relevant Entries by reading the Entries using their UIDs. The example below illustrates lazy loading using ExternalEntry.

This example creates a template Entry based on ExternalEntry where the matching Entries are all Message class instances and Message subclasses instances.

The ExternalEntry.setReturnOnlyUids(true) is called to indicate to the readMultiple method to return only UIDs.

The readMultiple method returns an Array where its first (and only element) m_MultipleUIDs attribute holds all relevant Entries' UIDs.

The Entries themselves can be read using the read API by creating a template Entry that contains only its UID. This is done by calling the __setEntryUID method that internally signals to the GigaSpaces Platform to locate and read this object using its UID and not by its matching attribute values.

String classname = Message.class.getName();
ExternalEntry ex = new ExternalEntry (classname, null, null);
ex.setReturnOnlyUids(true);
Entry[] result = space.readMultiple(ex, null, Integer.MAX_VALUE);
// Getting the first ExternalEntry from the readMultiple returned array
// The first entry - resultUIDs.m_MultipleUIDs - holds matching UIDs
ExternalEntry resUIDs = (ExternalEntry )result[0];
int max = resultUIDs.m_MultipleUIDs.length;
for (int i=0;i<max;i++ )
{
    Message temp = new Message ();
    temp.__setEntryUID(resultUIDs.m_MultipleUIDs[i]);
    //Reading entry using its ID
    Message m = (Message) space.read(temp, null, JavaSpace.NO_WAIT);
    System.out.println(m);
}

Parent-Child

In some cases, you might want to store Entries that include refereces to other space Entries in the space – i.e. an object graph.

The example code below demonstrates usage of UID operations.

The example writes 10 parent-child graphs into the space.

Two types of graphs exist in the example:

  • 5 graphs with the following values for the child objects: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
  • 5 graphs with the following values for the child objects: 0, 10, 20, 30, 40, 50, 60, 70, 80, 90.


The example demonstrates a simple approach locating all the parent objects that have two child objects with values of 1 and 2 – effectively join operation using UID operations.

This eventually returns the 5 first graphs.

Full example source code can be downloaded here.

Child class:

Child
package com.j_spaces.examples.parentchild;

import com.j_spaces.core.client.ClientUIDHandler;
import com.j_spaces.core.client.EntryInfo;
import com.j_spaces.core.client.MetaDataEntry;

public class Child extends MetaDataEntry{
	
	public Child(){}
	
	public Child(String id, String parentUID) 
	{
		String uid =ClientUIDHandler.createUIDFromName(id, this.getClass().getName());
		__setEntryInfo(new EntryInfo(uid,0));
		this.parentUID = parentUID;
		this.id = id;
	}

	public String parentUID;
	public Long field;
	public String id;
	
	public static String[] __getSpaceIndexedFields()
	  {
	    String[] indexedFields = { "parentUID", "field" };
	    return indexedFields;
	  }
	
	public String toString()
	{
		return "UID:" + __getEntryInfo().m_UID + " id:" + id + " value:" + field;
	}
}

Parent class:

Parent
package com.j_spaces.examples.parentchild;

import java.rmi.RemoteException;

import net.jini.core.entry.Entry;
import net.jini.core.entry.UnusableEntryException;
import net.jini.core.transaction.TransactionException;

import com.j_spaces.core.IJSpace;
import com.j_spaces.core.client.ClientUIDHandler;
import com.j_spaces.core.client.EntryInfo;
import com.j_spaces.core.client.ExternalEntry;
import com.j_spaces.core.client.MetaDataEntry;

public class Parent extends MetaDataEntry {
	public Parent() {
	}

	public Parent(int id) {
		String uid = ClientUIDHandler.createUIDFromName(id, this.getClass()
				.getName());
		__setEntryInfo(new EntryInfo(uid, 0));
	}

	public String childs_uid[];
	transient Child childs[];
	public Long field;
	
	public String getChildsDetails(IJSpace space) throws RemoteException, 
	TransactionException, UnusableEntryException
	{
		String ret="";
		Child[] childs = getChilds(space);
		for (int i=0;i<childs.length ; i++)
		{
			ret = ret + childs[i].toString() + "\n";
		}
		return ret;
		
	}
	public Child[] getChilds(IJSpace space) throws RemoteException, 
	TransactionException, UnusableEntryException
	{
		if (childs == null)
		{
			ExternalEntry templateUIDs = new ExternalEntry (childs_uid); 
			Entry results[] = space.readMultiple(templateUIDs , null , Integer.MAX_VALUE);
			childs = new Child[results.length];
			for (int i=0;i<results.length ; i++)
			{
				childs [i] =(Child)  ((ExternalEntry) results[i]).getEntry(space);
			}
		}
		return childs;
	}
	public String getChildUID()
	{
		String res ="";
		for (int i=0 ; i< childs_uid.length; i++)
		{
			res =res +childs_uid[i] + "\n";
		}
		return res;
	}
	
	public static String[] __getSpaceIndexedFields() {
		String[] indexedFields = { "field"};
		return indexedFields;
	}
}

Application:

Application
package com.j_spaces.examples.parentchild;

import java.rmi.RemoteException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import net.jini.core.entry.Entry;
import net.jini.core.entry.UnusableEntryException;
import net.jini.core.lease.Lease;
import net.jini.core.transaction.TransactionException;
import com.j_spaces.core.IJSpace;
import com.j_spaces.core.client.ExternalEntry;
import com.j_spaces.core.client.SpaceFinder;

public class ParentChildMain {

	static IJSpace space;

	public static void main(String[] args) {
		try {
			space = (IJSpace) SpaceFinder.find("/./mySpace?schema=cache");
			System.out.println("Write 10 parent/child graphs.\nWe will have 2 types of graphs:" +
					"\n5 graphs having the following values for the child objects:
					0,1,2,3,4,5,6,7,8,9" +
					"\nand another 5 graphs with the following values for the 
					child objects:0,10,20,30,40,50,60,70,80,90");
			for (int i = 0; i < 10; i++) {
				Parent parent = new Parent(i);
				Child childs[] = new Child[10];
				parent.childs_uid = new String[10];
				for (int j = 0; j < 10; j++) {
					childs[j] = new Child(i + "_" + j,
							parent.__getEntryInfo().m_UID);
					if (i% 2 ==0)
						childs[j].field = new Long(j);
					else
						childs[j].field = new Long(j * 10);
						
					parent.childs_uid[j] = childs[j].__getEntryInfo().m_UID;
				}
				space.write(parent, null, Lease.FOREVER);
				space.writeMultiple(childs, null, Lease.FOREVER);
			}

			System.out.println("Lets find all the parent object having 2 child object with 
			values 1 and 2 - effectively join");
			System.out.println("We need to make sure that both child objects 
			have the same parent");
			Entry childs_results1[] = getChildsbyValue(new Long(1));
			Set set1 = getParentUIDsSet(childs_results1);

			Entry childs_results2[] = getChildsbyValue(new Long(2));
			Set set2 = getParentUIDsSet(childs_results2);
			
			Set resultSet = AND(set1 , set2);

			Parent parents[] = getParentsfromUIDs(resultSet);
			
			System.out.println("Found " + parents.length +" matching Parent objects" );
			for (int i = 0; i < parents.length; i++) {
				System.out.println("Found Parent Object:" + parents[i]
						+ " - UID:" + parents[i].__getEntryInfo().m_UID + 
						" His childs are:\n"
						+ parents[i].getChildsDetails(space));

			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	static public Entry[] getChildsbyValue(Long value) throws RemoteException, 
	TransactionException, UnusableEntryException {
		Child child_template = new Child();
		child_template.field = value;
		return space.readMultiple(child_template, null,Integer.MAX_VALUE);
	}
	
	static public Set getParentUIDsSet(Entry entries[]) {
		HashSet result = new HashSet();
		for (int i = 0; i < entries.length; i++) {
			result.add(((Child) entries[i]).parentUID);
		}
		return result;
	}

	static public Parent[] getParentsfromUIDs(Set uids) throws UnusableEntryException, 
	RemoteException, TransactionException
	{
		Parent[] ret = null;
		String uids_str[] = new String [uids.size()]; 
		System.arraycopy(uids.toArray(),0,uids_str,0,uids_str.length);

		ExternalEntry child_uids_template = new ExternalEntry(uids_str);
		Entry childs_result[] = space.readMultiple(child_uids_template,null, Integer.MAX_VALUE);
		ret = new Parent[childs_result.length];
		for (int i=0;i<childs_result.length ; i++)
		{
			ret[i] = (Parent) ((ExternalEntry)childs_result[i]).getEntry(space);
		}
		return ret;
	}
	
	// find intersection between 2 sets with UIDs
	static public Set AND(Set set1, Set set2) {
		HashSet result = new HashSet();
		Iterator keys = set1.iterator();
		while (keys.hasNext()) {
			String key = (String) keys.next();
			if (set2.contains(key)) {
				result.add(key);
			}
		}
		return result;
	}
}

Expected output:

Write 10 parent/child graphs.
We will have 2 types of graphs:
5 graphs having the following values for the child objects:0,1,2,3,4,5,6,7,8,9
and another 5 graphs with the following values for the child objects:0,10,20,30,40,50,60,70,80,90
Lets find all the parent object having 2 child object with values 1 and 2 - effectively join
We need to make sure that both child objects have the same parent
Found 5 matching Parent objects
Found Parent Object:com.j_spaces.examples.parentchild.Parent@c954e - UID:-395274420^40^0^0^0 His childs are:
UID:-578745798^39^0_0^0^0 id:0_0 value:0
UID:-578745798^39^0_1^0^0 id:0_1 value:1
UID:-578745798^39^0_2^0^0 id:0_2 value:2
UID:-578745798^39^0_3^0^0 id:0_3 value:3
UID:-578745798^39^0_4^0^0 id:0_4 value:4
UID:-578745798^39^0_5^0^0 id:0_5 value:5
UID:-578745798^39^0_6^0^0 id:0_6 value:6
UID:-578745798^39^0_7^0^0 id:0_7 value:7
UID:-578745798^39^0_8^0^0 id:0_8 value:8
UID:-578745798^39^0_9^0^0 id:0_9 value:9

Found Parent Object:com.j_spaces.examples.parentchild.Parent@39452f - UID:-395274420^40^8^0^0 His childs are:
UID:-578745798^39^8_0^0^0 id:8_0 value:0
UID:-578745798^39^8_1^0^0 id:8_1 value:1
UID:-578745798^39^8_2^0^0 id:8_2 value:2
UID:-578745798^39^8_3^0^0 id:8_3 value:3
UID:-578745798^39^8_4^0^0 id:8_4 value:4
UID:-578745798^39^8_5^0^0 id:8_5 value:5
UID:-578745798^39^8_6^0^0 id:8_6 value:6
UID:-578745798^39^8_7^0^0 id:8_7 value:7
UID:-578745798^39^8_8^0^0 id:8_8 value:8
UID:-578745798^39^8_9^0^0 id:8_9 value:9

Found Parent Object:com.j_spaces.examples.parentchild.Parent@1ed13da - UID:-395274420^40^4^0^0 His childs are:
UID:-578745798^39^4_0^0^0 id:4_0 value:0
UID:-578745798^39^4_1^0^0 id:4_1 value:1
UID:-578745798^39^4_2^0^0 id:4_2 value:2
UID:-578745798^39^4_3^0^0 id:4_3 value:3
UID:-578745798^39^4_4^0^0 id:4_4 value:4
UID:-578745798^39^4_5^0^0 id:4_5 value:5
UID:-578745798^39^4_6^0^0 id:4_6 value:6
UID:-578745798^39^4_7^0^0 id:4_7 value:7
UID:-578745798^39^4_8^0^0 id:4_8 value:8
UID:-578745798^39^4_9^0^0 id:4_9 value:9

Found Parent Object:com.j_spaces.examples.parentchild.Parent@1b25a82 - UID:-395274420^40^2^0^0 His childs are:
UID:-578745798^39^2_0^0^0 id:2_0 value:0
UID:-578745798^39^2_1^0^0 id:2_1 value:1
UID:-578745798^39^2_2^0^0 id:2_2 value:2
UID:-578745798^39^2_3^0^0 id:2_3 value:3
UID:-578745798^39^2_4^0^0 id:2_4 value:4
UID:-578745798^39^2_5^0^0 id:2_5 value:5
UID:-578745798^39^2_6^0^0 id:2_6 value:6
UID:-578745798^39^2_7^0^0 id:2_7 value:7
UID:-578745798^39^2_8^0^0 id:2_8 value:8
UID:-578745798^39^2_9^0^0 id:2_9 value:9

Found Parent Object:com.j_spaces.examples.parentchild.Parent@541b02 - UID:-395274420^40^6^0^0 His childs are:
UID:-578745798^39^6_0^0^0 id:6_0 value:0
UID:-578745798^39^6_1^0^0 id:6_1 value:1
UID:-578745798^39^6_2^0^0 id:6_2 value:2
UID:-578745798^39^6_3^0^0 id:6_3 value:3
UID:-578745798^39^6_4^0^0 id:6_4 value:4
UID:-578745798^39^6_5^0^0 id:6_5 value:5
UID:-578745798^39^6_6^0^0 id:6_6 value:6
UID:-578745798^39^6_7^0^0 id:6_7 value:7
UID:-578745798^39^6_8^0^0 id:6_8 value:8
UID:-578745798^39^6_9^0^0 id:6_9 value:9


GigaSpaces 6.0 Documentation Contents (Current Page in Bold)

    Java

    C++

    .NET

    Middleware Capabilities

    Configuration and Management

Add GigaSpaces wiki search to your browser search engines!
(works on Firefox 2 and Internet Explorer 7)

Labels