Externalizable Support

  Search Here
Searching XAP 6.0 Documentation

                                               

Summary: Using Externalizable to boost remote space performance with JavaSpaces operations.

Overview

To solve the performance problems associated with making a class Serializable, the serialization mechanism allows you to declare that a class is Externalizable. When the ObjectOutputStream writeObject() method is called, it performs the following sequence of actions:

  • Tests to see if the object is an instance of Externalizable. If so, it uses externalization to marshall the object.
  • If the object isn't an instance of Externalizable, it tests to see whether the object is an instance of Serializable. If so, it uses serialization to marshall the object. If neither of these two cases apply, an exception is thrown.

Externalizable is an interface that consists of two methods:

public void readExternal(ObjectInput in);
public void writeExternal(ObjectOutput out);

These have a role similar to the role that the readObject() and writeObject() methods have for serialization. There are, however, some very important differences:
readExternal() and writeExternal() are part of the Externalizable interface. An object cannot be declared as Externalizable without implementing these methods.

The major difference lies in how these methods are used. The serialization mechanism always writes out class descriptions of all the serializable superclasses. Also, it always writes out the information associated with the instance when viewed as an instance of each individual superclass.

The Externalization mechanism writes out the identity of the class (which boils down to the name of the class and the appropriate serialVersionUID). It also stores the superclass structure and all the information about the class hierarchy. But instead of visiting each superclass and using it to store some of the state information, it simply calls writeExternal() on the local class definition.
The Externalization mechanism stores all the metadata, but writes out only the local instance information.

When using the Entry class with the JavaSpace API, you may implement the Externalizable mechanism. This can be done to control serialization and deserialization when the Entry is sent into the space (Write and Update Operations) and when it is sent back to the client (read and take operations). This will optimize the remote call when using Remote Space configuration for single, partitioned and replicated space topologies.

In order to activate externalizable support, the IJSpace multiple API, that includes the readMultiple, writeMultiple, and takeMultiple operations, must operate with an object array that is an instance of Externalizable[], or have the first object in the array implement Externalizable, for example:

public class Message implements Externalizable, Entry {
    ...
}
 

public void writeData()  {
    // create the new array
    Externalizable[] data = new Externalizable[size];

    // fill the data array
    for (index = 0; index < size; index++) {
        data[index] = new Message(...);
        ...
    } 

    // write the data to space
    spaceProxy.writeMultiple(data, transaction, lease);
}

Otherwise, even if an Entry implements the Externalizable interface, it still operates through the regular serialization mechanism.

Externalizable is supported with the Native Serialization mode.

Example

Message Implements Entry

Here is a simple class that implements the Entry interface:

Message
package com.j_spaces.examples.benchmark;

import net.jini.core.entry.Entry;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class Message implements Entry{
	public byte[] m_content;
	public Long m_counter;
	private static final long serialVersionUID = 1L;
	public ArrayList<GregorianCalendar> list;
	final private static String[] INDEXED_FIELDS = { "m_counter" };

	public Message () {
	}

	public Message (long initVal, byte[] content) {
		m_content = content;
		m_counter = initVal;
		if (m_content !=null)
			generateData(10);
	}

	public void generateData(int capacity) {
		if (capacity > 0) {
			list = new ArrayList<GregorianCalendar>(capacity);
			for (int i = 0; i < capacity; i++) {
				int year = (int) (Math.random() * 2000);
				int month = (int) (Math.random() * 12);
				int day = (int) (Math.random() * 31);
				list.add(i, new GregorianCalendar(year, month, day));
			}
		}
	}

	public void setContent(byte[] content) {
		this.m_content = content;
		generateData(10);
	}

	public void setCounter(long counter) {
		this.m_counter = counter;
	}

	@Override
	public String toString() {
		return getClass() + "_" + m_counter + "_" + m_content;
	}

	public static String[] __getSpaceIndexedFields() {
		return INDEXED_FIELDS;
	}
}

Message Implements Externalizable

Here is the same class with the Externalizable interface implemented.
See how the list field that is ArrayList<GregorianCalendar> is serialized and deserialized:

Message
package com.j_spaces.examples.benchmark;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import net.jini.core.entry.Entry;

public class Message implements Externalizable,Entry{
	private static final long serialVersionUID = 1L;
	final private static String[] INDEXED_FIELDS = { "m_counter" };
	public byte[] m_content;
	public Long m_counter;
	public ArrayList<GregorianCalendar> list;

	public Message() {
	}

	public Message(long initVal, byte[] content) {
		m_content = content;
		m_counter = initVal;
		if (m_content !=null)
			generateData(10);
	}

	public static String[] __getSpaceIndexedFields() {
		return INDEXED_FIELDS;
	}

	public void writeExternal(ObjectOutput out) throws IOException {
		if (m_counter == null)
			out.writeLong(0);
		else
			out.writeLong(m_counter);
		
		if (m_content != null )
		{
			out.writeInt(m_content.length);
			out.write(m_content ,0, m_content.length);
		}
		else
		{
			out.writeInt(0);
		}
			
		if (list != null) {
			out.writeBoolean(true);
			out.writeInt(list.size());
			for (GregorianCalendar date : list) {
				out.writeInt(date.get(Calendar.YEAR));
				out.writeInt(date.get(Calendar.MONTH));
				out.writeInt(date.get(Calendar.DAY_OF_MONTH));
			}
		} else {
			out.writeBoolean(false);
		}
	}

	public void readExternal(ObjectInput in) throws IOException,
			ClassNotFoundException {
		m_counter = (Long) in.readLong();
		Integer m_content_length =in.readInt(); 
		if (m_content_length >0) 
		{
			m_content = new byte[m_content_length.intValue()];
			in.read(m_content, 0 , m_content_length.intValue());
		}
		boolean islist = in.readBoolean();
		if (islist )
		{
			int capacity = (Integer) in.readInt();
			list = new ArrayList<GregorianCalendar>(capacity);
			for (int i = 0; i < capacity; i++) {
				int year = in.readInt();
				int month = in.readInt();
				int day = in.readInt();
				list.add(i, new GregorianCalendar(year, month, day));
			}
		}
	}

	public void generateData(int capacity) {
		if (capacity > 0) {
			list = new ArrayList<GregorianCalendar>(capacity);
			for (int i = 0; i < capacity; i++) {
				int year = (int) (Math.random() * 2000);
				int month = (int) (Math.random() * 12);
				int day = (int) (Math.random() * 31);
				list.add(i, new GregorianCalendar(year, month, day));
			}
		}
	}

	public void setContent(byte[] content) {
		this.m_content = content;
		generateData(10);
	}

	public void setCounter(long counter) {
		this.m_counter = counter;
	}

	@Override
	public String toString() {
		return getClass() + "_" + m_counter + "_" + m_content;
	}
}

Performance Tests Results

Externalizable is not Supported by the C# and C++ API.

Limitations and Known Issues

  • FIFO is supported when the Entry class extends the MetaDataEntry class. In this case you should call super._writeExternal() at your Entry writeExternal() implementation. FIFO is not supported when the Entry class does not extend the MetaDataEntry class, and when using the IJSpace.setFIFO() method.
  • When registering for notifications, the notify template implementing the Externalizable interface will not have its writeExternal/readExternal called. Notifications in FIFO mode will be delivered in FIFO mode.
  • Versioning is not supported.
  • Optimistic locking is not supported.


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