Distributed objects
PART introduces the concept of distributed objects, which are objects that can be used to represent some application state that needs to be shared and synchronised among many processes. A fundamental characteristic of a distributed object is that it may exist as several copies, held by several processes simultaneously. For example, an application process running in a mobile phone could create an instance of a distributed object, which could then be copied to another process running on a laptop computer. The result would be an object which existed both on the mobile phone and on the laptop at the same time. The process of copying a distributed object from one process to another is called replication. The new object copy which is created as a result of the replication is called a replica. The first instance of a particular distributed object is called the master. Thus, a distributed object is represented by a master copy, and zero or more replicas.There may exist only one copy (master or replica) of a particular distributed object in any given process. If an object is replicated to the same processes several times, PART makes sure that only one replica of the replicated object is created. Both the master and the replicas can be replicated. I.e., a process that holds a replica of an object may choose to replicate the object to another process.
The shared state of a distributed object is represented by the values of its properties. Properties are <group, name, value> tuples that are created dynamically during run-time (typically when an object instance is created). Only the values of a distributed object's properties will be copied during a replication, not the values of its class variables, and only updates to properties (no class variables) may be reflected in remote replicas of an object.
When a distributed object is replicated, the state of the new replica instance will be the same as the source instance (master or another replica). However, the platform also provides various mechanisms by which the state of the replicas can be kept in sync as the state is changed. Thus, if the state of a replica is modified, the programmer can choose how the modification is reflected in the other replicas of the same object. The synchronisation of state (property values) in-between object replicas is main reason for using properties instead of ordinary class variables. Distributed object classes can indeed have many ordinary class variables, but the updates to such variables in the master or a replica will be purely local, i.e., no other copy of the same object will be affected.
The IpObject class
Distributed objects are supported by the platform via a specific class, IpObject. Although instances of IpObject can be created directly using the new operator, a more common use is for the application to create application specific sub-classes. For instance, a game application that needs to use distributed objects could introduce a new class, GameObject, by extending IpObject:public class GameObject extends
IpObject {
…
}
NOTE In order for distributed object replication to work, all distributed object sub-classes must provide a public constructor with no parameters. The reason is that in order for PART to be able to create a new object replica during the replication process, it needs to use this constructor. A distributed object class can of course have as many different constructors as it wants as long as one of them is public and takes no arguments. For example:
public class GameObject extends
IpObject {
// Needed in order for replication to
work
public GameObject()
{
…
}
public GameObject(int aParameter, String
anotherParameter)
{
…
}
}
Instances of distributed object classes (i.e., sub-classes of IpObject) are typically created by using the new operator, but the application can of course introduce some factory mechanism if more control over object creations is needed.
Distributed object identifiers
All instances of sub-classes of IpObject are associated to a unique identifier of type IpIdentifier. The identifier of a distributed object can be retrieved using the getId method:IpIdentifier id = obj.getId();
Calling getId on replicas of the same distributed object in different processes will return the same identifier. Thus, an object identifier can safely be sent from one process to another with the assumption that it will represent the same object in both processes.
The IpObject class also provides a static method for retrieving distributed object instances held by the local process:
GameObject obj =
(GameObject)IpObject.getObject(Id);
Creating distributed object properties
Properties can be added to a distributed object via the createProperty and addProperty methods of the IpObject class. The createProperty method should only be used in the constructor of a distributed object class, while addProperty can be used anywhere outside the constructor to add new properties to an object instance during run-time.Properties are represented by a (string) name and a (string) value. Properties also have a group "attribute", which is the name of the group to which the property belongs. All properties with the same group name are thus considered to be part of the same group. If null is given as the group name when a property is created, it will be made a member of the default group. The name of the default group is given by IpObject.DEFAULT_PROP_GROUP attribute. The IpObject class provides a number of methods for manipulating properties, described in the following sections.
All property values must be strings, although there are some methods by which property values can be supplied as integer or floats for convenience, e.g., addPropertyViaInt. However, all property values are stored as strings, no matter in which "form" they are supplied.
The createProperty method is intended to be used in the constructor of a distributed object class to create properties that all instances of the class should have. The method is protected, which means that its not directly accessible to code outside of the class.
public class GameObject extends
IpObject {
public GameObject()
{
// Add
some "class" specific properties.
createProperty(null, "name", "fred");
createProperty(null, "age", "5");
createProperty("group1", "speed", "3.14");
}
…
}
In the example above, the class GameObject introduces three properties, name, age and speed, with values "fred", "5" and "3.14". The name and age properties belongs to the default group since the group name given is null, while speed belong to the group group1. All instances of GameObject will thus have these properties after being created.
GameObject obj1 = new GameObject();
GameObject obj2 = new GameObject();
The addProperty method can be used to add additional properties to an individual distributed object instance, once it has been created.
// Add another property to obj1 only,
obj2 will not be affected
try {
obj1.addProperty("test", "hello");
} catch (IpVetoException e)
// hmm, not allowed
}
Adding a property to an object in this way is considered an update of the object. This means that the master object can veto the addition of the property by throwing an IpVetoException. How a distributed object class programmer can override object updates, e.g., additions of properties, is described here.
If the property addition is allowed, PART takes care of updating all copies of the object (both master and replicas) so that all of them will get the new property. Whenever a property is added to an object via addProperty, an IpObjectEvent of type PROP_ADD is posted to the applications event handler in all processes that holds a copy of the object.
public void handleEvent(IpEvent event)
{
if
(event.getType().equals(IpObjectEvent.PROP_ADD)) {
IpObjectEvent e = (IpObjectEvent)event;
String
name = e.getPropertyName();
String
group = e.getPropertyGroup();
IpObject
obj = e.getObject();
IpIdentifier procId = e.getProcessId();
System.out.println("Property "
+ group + "." +
name
+ " was added to object "
+ obj.getId()
+ " by process "
+ procId);
}
}
The IpObject class introduces a method, replicaUpdateCb, that also gets called when a property is added (as well as updated or removed) to an object. The method is called in both the master and all replicas. By overriding this method, it's possible for a programmer to catch an object update and for instance introduce events that are more high level than the PART events. Or the object could perhaps provide a listener mechanism, allowing callbacks to be fired when the object is updated.
public class GameObject extends
IpObject {
public replicaUpdateCb(IpObjectEvent e)
{
// I do
not want the application to have to listen to
//
property events, so I introduce a more high-level event
if
(e.getType().equals(IpObjectEvent.PROP_ADD)) {
// invoke listeners
…
}
}
…
}
Retrieving property values
The values of an object's properties can be accessed via one of the getProperty methods of the IpObject class. A value of null is returned if the object doesn't have a property with the given group and/or name.String val = obj1.getProperty("name");
System.out.println("The name of the object is " + val);
When using getProperty, the value returned is always the value stored in the local copy of the distributed object, i.e., the copy on which getProperty is called. Since a distributed object may be represented by several copies, held by many processes, and the value of a particular property may differ in each replica (more about this below), it's important to understand that the value returned is the local property value, and not the value held by any remote (e.g., the master) copy of the same object.
There are also come convenience methods that allows the programmer to retrieve the value as an integer or float. Note that these methods should only be used if the value has been set using a corresponding set method:
float fval =
obj1.getPropertyAsFloat("group1", "speed");
Updating properties
The values of object properties can be manipulated via the setProperty method of the IpObject class.try {
obj1.setProperty(null, "name", newName);
} catch (IpException e) {
// hmm, failure
}
When updating properties, two different exceptions may be thrown.
- An IpNoSuchPropertyException exception is thrown if the object has no property matching the given name and group.
- An IpVetoException exception is thrown if the update is not allowed by the master object.
Whenever a property is updated, an IpObjectEvent of type PROP_UPDATE is posted to the application's event handler. The object's replicaUpdateCb method is also called.
Browsing properties
When writing a distributed object class, the programmer has full control of which properties will be added as instances are created, e.g., how many there are, what their names are, and so on. However, since properties may be added dynamically to objects after their creation, PART provides some methods that allows the programmer to do iterations over all properties groups and names.The getAllPropertyGroupNames method can be used to get all the property group names of an object. For instance, the following code will print the names of all property groups of a distributed object.
Enumeration names =
obj.getAllPropertyGroupNames();
while (names.hasMoreElements()) {
System.out.println((String)names.nextElement());
}
Using a group name, it is then possible to get the name of all object properties belonging to that particular group via the getAllPropertyNames method:
Enumeration names =
obj.getAllPropertyNames(groupName);
while (names.hasMoreElements()) {
System.out.println((String)names.nextElement());
}
The following code will print the group name, name and value of all properties of a distributed object:
Enumeration groups = obj.getAllPropertyGroupNames();
while (groups.hasMoreElements()) {
String group =
(String)groups.nextElement();
Enumeration names =
obj.getAllPropertyNames(group);
while (names.hasMoreElements()) {
String
name = (String)names.nextElement();
String
value = obj.getProperty(group, name);
System.out.println("Prop "
+ group + "." + name + " " + value);
}
}
Removing properties
Properties can be removed from an object using the removeProperty method.try {
obj.removeProperty(group, name);
} catch (IpException e) {
// failure
}
Similar to other property manipulation method, removeProperty may throw an exception, indicating an error, for instance as a result of the removal not being allowed by the master process.
When a property is removed from a distributed object, an IpObjectEvent of type PROP_REMOVE is sent to the event handler in all processes holding a copy of the object. The object's replicaUpdateCb method is also called.
Vetoing property updates
The veto mechanism is something that can be used by the programmer to prevent unwanted changes to a distributed object. The changes that can be vetoed are addition of properties, updates of property values and removals of properties.In order to veto proposed changes to an object, the propertyUpdateResolve method of the IpObject class needs to be overridden by a sub-class. Whenever the addProperty, setProperty or removeProperty methods are called by the application code, PART will call the propertyUpdateResolve method in the master object to check whether the update is ok or not.. If this method throws an IpVetoException, the update will be cancelled and the exception will be delivered to the application code. If propertyUpdateResolve returns without casting an exception, the update will be allowed. This will happen by default if propertyUpdateResolve is not overridden. Note that if there exist no working network route between the master and replica processes, all replica updates will be vetoed, since then there is no way for PART to check the update with the master.
For instance, the following method, placed in a distributed object sub-class, will make sure that the string value of the object's name property will not be longer than 9 characters:
void propertyUpdateResolve(int type,
String group, String name, String value,
IpIdentifier
sourceProcId)
throws IpVetoException
{
if (type == IpObject.PROP_SET) {
// prevent the value of the
name property from being longer
// than 10 characters
if (name.equals("name")
&& (value.length() > 10)) {
throw
new IpVeoException("name too long");
}
}
}
Note that the propertyUpdateResolve method is always called in the master copy of the distributed object, and not in the replicas, even if it was on a replica that the update method (e.g., setProperty) was invoked. This means that if the update method is called on a replica, PART will send the details of the proposed update to the process holding the master, then call propertyUpdateResolve in the master, and finally, depending on the result, set the new value in the master or abort the update. PART will also send a message back to the process proposing the update, which will then update the replica or throw an IpVetoException depending on the "verdict". Other replicas of the same object won't be notified about the property update until they get an update due to having subscribed to the master, or by explicitly synchronising the replica with the master, as described in the next section. The update process for a call to the setProperty method is illustrated by the figure below. Note that this process also ensures that if several processes try to update the same process simultaneously, these updates will be serialised at the master, which eliminates the risk of inconsistencies due to concurrent updates.
Property update synchronisation
The main reason for using properties instead of "normal" class variables is that their values can be synchronised between replicas of the same distributed object. When a property is successfully updated, the value is immediately changed in the master object and the replica on which setProperty was called (if method was not called directly on the master). All other replicas of the same object are unaffected by the update. However, PART provides two mechanisms for synchronising property values of replicas with the values held by the master, called automatic synchronisation or non-automatic synchronisation.Automatic property synchronisation
Automatic synchronisation is based on a subscription mechanism. A process that holds a replica of a distributed object can subscribe to updates made to the master. If no subscription is active, the properties of the replica are not updated as a result of updates to properties of the master. When a distributed object is replicated, the new replica is by default not subscribed by the destination process. Subscriptions must be explicitly activated by the application code.Subscriptions are only valid for the replica in which they are activated. This means that one process, holding a replica of a particular distributed object, could subscribe to changes made to the master, while another process, also holding a replica of the same object, doesn't subscribe to updates at all. The value of a property in one replica can thus be different than the value in another, which might seem as a strange and potentially dangerous situation. However, since PART is aimed at supporting development of pervasive applications that run in unreliable networking environment, the model gives the programmer a chance to choose how much synchronisation is necessary between replicas, even on a per-replica basis. This means that it's possible to adjust the synchronisation level to the assumed networking conditions, and even change the level during run-time. This can be contrasted with a solution where PART tries to uphold a very tight synchronisation between replica values in different processes, which might be very hard to achieve in an unstable networking environment where connections between replicas fail regularly, possibly leading to all sorts of error conditions.
Subscriptions can be activated on per-object or a per-property level. If a per-object subscription is activated, all of the object's properties are subscribed in the same way. This means that if any of the object's properties are changed in the master, the change will be reflected in the subscribed replica. Per-property subscriptions allows the application to subscribe to selected properties only. If a subscribed property is updated in the master, the same property will be updated in the subscribed replica. However, if any other property is updated, the update will not be reflected in the replica.
When activating subscriptions, a process that holds a replica can select at which rate changes should be propagated from the process that holds the master. This is done by specifying a subscription interval. The interval defines how often changes to the master should be reported to the subscribed replica. The interval is given in milliseconds. For example, an interval of 1000 means that changes to the master will be only be reflected in the subscribed replica at a maximum of once per second. If the master is updated every two seconds, the subscribed replica will also be updated every two seconds, but if the master is updated every 50 milliseconds, the subscribed replica will only be updated every second. The table below illustrates how the value of a property changes in the master and a subscribed replica if the update rate is 100 milliseconds and the subscription interval is 400 milliseconds.
Time | Master value | Replica value |
0 ms | 0 | 0 |
100 ms | 1 | 0 |
200 ms | 2 | 0 |
300 ms | 3 | 0 |
400 ms | 4 | 4 |
500 ms | 5 | 4 |
600 ms | 6 | 4 |
700 ms | 7 | 4 |
800 ms | 8 | 8 |
900 ms | 9 | 8 |
If a subscribing process wants to receive all updates made to the master object, the interval 0 should be used.
Properties can be subscribed using the subscribe or subscribeAll methods of the IpObject class. Calling these methods on the master object has no effect, since the master will always hold the most recent property values.
GameObject obj =
(GameObject)event.readObject();
// subscribe to properties “name”, “age”, “speed”, interval 1000
obj.subscribe(null, “name”, 1000);
obj.subscribe(null, “age”, 1000);
obj.subscribe(“group1”, “speed”, 1000);
The subscribe method can be called several times to update the
subscription interval:
// we want updated fairly quickly
obj.subscribe(“group1”, “speed”, 100);
…
// slow down
obj.subscribe(“group1”, “speed”, 3000);
The subscribeAll method can be used to subscribe to all object properties using the same interval.
obj.subscribeAll(1500);
Whenever a local replica is updated to reflect changes to the master, PART sends an IpObjectEvent of type PROP_UPDATE to the application’s event handler.
To remove a subscription, use the unsubscribe or unsubscribeAll methods of the IpObject class:
obj.unsubscribe(null, “age”);
obj.unsubscribeAll();
A process need not be directly connected to the process holding the master copy of a distributed object in order to subscribe to property updates. If no direct connection exists between the processes holding the master and the subscribed replica, property updates will be routed to the subscribing process via some other processes, see the figure below.
The property subscription mechanism uses the concept of leases to prevent unnecessary network traffic in case subscribing processes crash or network connections break. The principle is that when a process subscribes to property updates, the subscription is only valid for a certain amount of time. Unless the process renews the subscription within this time, the master process will cancel the subscription, meaning that it will no longer inform the subscribing process about property updates. The subscription renewal mechanism is automatically handled by PART, but the renewal rate (i.e., the rate at which the subscriber renews its subscriptions) may be accessed and modified by the application via the getSubscriptionRenewInterval and setSubscriptionRenewInterval methods of the IpSystem class.
// Change the rate at which
subscriptions are being renewed to 30
// seconds
IpSystem.setSubscriptionRenewInterval(30);
When an object subscription is renewed, the subscribing process sends a message to the process holding the master with information on all active property subscriptions. After receiving such a message, the master process will send a reply back to the subscribing process confirming the renewal. This means that at least two "problems" may occur when renewing subscriptions :
- The master process doesn't receive a renew message in time. This will happen for instance if the network route in-between the two processes is somehow broken. This will cause the master process to cancel the subscription. An effect of this behaviour is that if the subscribing process is stopped or crashes, the master process will eventually cancel the subscription and stop trying to send property updates to that particular process.
- The subscribing process doesn't receive the renew confirm message from the master process. This may again happen if the network connection is somehow broken, but also if the master process has being stopped or crashed. Note that this does not cause the subscribing process to cancel the subscription. The property will still be considered as being subscribed, which means that the process will keep on trying to renew the subscription. This means that if the problem that prevented the confirm message to reach the subscribing process (network, master not running, etc) is fixed, there is a chance that the subscription will start working again.
- Each time a subscribing process receives a renew confirm message from a master process, PART sends an IpSubscriptionEvent of type SUBSCRIPTION_CONFIRM to the application's event handler. This event is only generated on the subscribing process.
- If a subscribing process hasn't received a renew confirm message from the master within one interval after sending a renew message, a IpSubscriptionEvent of type SUBSCRIPTION_TIMEOUT is sent to the application's event handler. This will happen if problem 2 above above occurs. This event is only generated on the subscribing process.
- If the master process hasn't received a subscription renew message within time, a IpSubscriptionEvent of type SUBSCRIPTION_CANCEL is sent to the application's event handler. This will happen if problem 1 above occurs. This event is only generated on the master process.
Non-automatic property synchronisation
The state of distributed object replicas can be explicitly synchronised upon request by the application via the synchronise and synchroniseProperty methods of the IpObject class. These methods cause all or a specific replica property to be synchronised with another replica, or with the master.Synchronising a replica with the master will cause the values of all replica properties to be set to the corresponding values of the master. Synchronising a replica with another replica will cause the property values of the synchronised replica to be set to the most recent value held by any of the replicas. To know which value is the most recent, PART uses version numbers. Whenever a master property is updated, its version number is increased. If a master property update is reflected in a replica, the replica stores the version number corresponding to its current property value. By comparing the version numbers of the same property in two different replicas, PART can then determine which one is more recent. The tables below show how the values of properties “age” and “speed” are affected by a synchronisation of Replica1 with Replica2. Note that property version numbers are not visible to the application programmer.
Property | Replica1 - value(version) | Replica2 - value(version) |
age | 5 (3) | 4 (4) |
speed | 1.2 (5) | 1.7 (3) |
Table1: Values and version numbers of replica properties before the synchronisation
Property | Replica1 - value(version) | Replica2 - value(version) |
age | 4 (4) | 4 (4) |
speed | 1.2 (5) | 1.7 (3) |
Table2: Values and version numbers of replica properties after synchronisation Replica 1 with Replica2. Note that Replica2's properties are unaffected by the synchronisation.
A synchronisation has no persistent effect on the replicas (or master) involved, meaning that PART will not try to keep the replicas synchronised once the synchronisation has been completed.
The synchronise and synchroniseProperty methods come in two versions, one that synchronises a distributed object replica with the master, and one that synchronises a local replica with a corresponding replica in another process.
// Synchronise the local replica with
the master
obj1.synchronise();
// Synchronise property using another replica
obj2.synchroniseProperty(null, "age", remoteProcId);
Since synchronisation involves network communication, the method may throw exceptions if there was some problem when communicating with the remote process.
Cancellations of property subscriptions
If a process has started to subscribe to properties of an object, the subscription will be valid until explicitly cancelled via the unsubscribe or unsubscribeAll methods of the IpObject class.// Will cause all properties to
become unsubscribed
obj.unsubscribeAll();
// Will cause the age property to become unsubscribed
obj.unsubscribe(null, “age”);
Calling unsubscribe or unsubscribeAll will set the local property subscription status to "not subscribed". This information is then immediately sent to the master process in order to cancel the subscription. However, if the master doesn’t confirm the unsubscription in the same way as renewed subscriptions, PART will retry to notify the master about the unsubscription using the same mechanism as is being used to renew subscriptions. In fact, the subscription update messages that are sent from the subscribing process to the master as described above do actually contain information about unsubscriptions as well as subscriptions. This means that the “renew mechanism” will actually handle unsubscriptions as well, i.e., if the master doesn’t confirm the unsubscription for some reason (e.g., network problems), the renew mechanism will make sure that the unsubscribe information will be re-sent (and hopefully confirmed by the master eventually).
Replicating distributed objects
Replication is the process of creating a copy of an existing distributed object in a new process. This involves marshalling the values of all properties of the replicated object into a message, sending the message to the remote process, unpacking the message, creating a new instance of the distributed object class using the empty constructor and setting the property values in the new instance to those encoded in the message. All of these tasks are handled automatically by PART and are mostly invisible to the application programmer. However, it is important to understand the underlying principles of object replication since they impose some requirements that must be met by the application in order for replication to work. There are three basic rules that the application programmer must be aware of to be able to use distributed object replication:- Distributed object classes must derive from the platform class IpObject
- Distributed object classes must have a public empty constructor. The reason for this is that during replication, the platform needs to automatically create new instances of distributed object classes introduces by the application, and uses the empty constructor to do so.
- All processes to which a distributed object may be replicated must have the corresponding distributed object class in their class path. The platform is not able to transfer an object's class file to the destination process during replication, so all classes must already exist at the remote processes to which distributed objects are replicated. If this is not the case, the receiving process won't be able to create the replica.
Push replication
Push replication means that a process that holds a copy of a distributed object initiates an operation that will cause a copy of the object to be created in a remote process.One of the more simpler ways of replicating a distributed object is to encode the object into a network event and then sending the event to a remote process. When the remote process receives the event and decodes the object, the replication is completed (i.e., the object will now exist in both processes).
For instance, on the sender side:
GameObject obj = new GameObject(4,
5.1);
IpIoStream s = new IpIoStream();
s.writeObject(obj);
IpNetworkEvent event = new IpNetworkEvent("myGameEvent", destProcId, s);
event.send();
The event is eventually be delivered to the event handler in the destination process, where the object can be decoded from the payload. As a result, a copy of the object now exists in this process also.On the receiver side;
public void handleEvent(IpEvent event)
{
if
(event.getType().equals("myGameEvent")) {
IpIoStream s = receivedEvent.getPayload();
GameObject obj = (GameObject)s.readObject();
}
}
If an object that is sent to a remote process already exists on this process, PART will not create a new copy of the object. Instead, the existing copy is used to decode the data (property values) stored in the event payload. This may cause the existing replica to change, since some or all of the property data stored in the event may be more recent than the one held by the existing object (is determined by comparing property version number with the version number stored in the event).
Using events to replicate objects to remote processes may not always be possible since it requires the receivers to explicitly handle the event and decode the object. In some cases it might be desirable to replicate an object to a remote process that has not been written to handle for instance an event containing the object. This can be achieved by using the replicate method of the IpObject class.
// Replicate the object to process
identified by procId
obj.replicate(procId);
The replicate method will create an copy of a distributed object in a remote process without any "help" from the application code. However, note that in order for this to be possible, the object class must be loadable from the classpath of the remote process. This means that it isn't possible to replicate an object of class X to a remote process that knows nothing about class X.
Pull replication
Pull replication is the opposite of push replication in that it is the process that has no object replica that initiates the replication.A process can retrieve distributed objects held by remote processes by performing an object search. The search is initiated by first creating an object pattern, and then sending the pattern to one or several remote processes. When receiving such a pattern, a process performs a match between the pattern and all the distributed object replicas that it holds. Objects that match the pattern are then sent back to the process from where the search originated. It's possible for the origin process to specify a maximum number of object to be returned from each process. Patterns are described more in this section.
The IpSystem class provides two methods for doing object searches, one synchronous and one asynchronous. The synchronous version allows a pattern to be sent to a given remote process and then blocks, waiting for the reply. A timeout parameter allows the caller to have the search timeout if no results have been received within a given time.
try {
IpObject[] result =
IpSystem.searchObjects(destProcId,
pattern,
maxMatches,
timeout);
if (result == null) {
System.out.println("Got 0 objects");
} else {
System.out.println("Got " + result.length + " objects");
}
} catch (IpTimeoutException e) {
// timeout occured before any result was
returned
}
The asynchronous search method allow the pattern to be sent to a given process, or to be broadcasted to all processes reachable from the local process. The method is non-blocking, meaning that it returns immediately. Search results are instead passed to the application via events of type IpObjectSearchEvent sent to the event handler.
public void handleEvent(IpEvent event)
{
if (event instanceof
IpObjectSearchEvent) {
IpObjectSearchEvent e = (IpObjectSearchEvent)event;
IpObject[] objs = e.getObjects();
if (objs
== null) {
System.out.println("Got 0 objects from process "
+
e.getProcessId());
} else {
System.out.println("Got " + objs.length + " objects "
+ "from
process " + e.getProcessId());
}
}
}
Note that since PART has no way of knowing how many results will be received (if any), PART doesn't know how many results to expect and when an asynchronous search thus is complete.
Removing replicated objects
If a process that has replicated a distributed object wants to remove the object, it needs to notify PART via the release method.// Tell PART that we are no longer
interested in this object
obj.release();
Note however that since Java doesn't allow objects to be explicitly removed, the release method doesn't actually cause the object to be removed, it merely tells PART to remove all of its references to the object.
The releaseAllObjects has the same effect as release, the only difference being that PART removes its references to all replicated objects, not just a single copy (the references to the local process object is however not removed).
// Get rid of everything
IpObject.releaseAllObjects();
Searching for objects in remote processes
As mentioned above, distributed objects can be found in remote processes by performing object searches. Such searches are typically used in order to do replication, i.e., to copy objects from a remote process to the local process. However, sometimes it’s desirable to locate remote objects without triggering replication. The searchObjectIds method of the IpSystem class allows an object search to be performed in the same way as described in the section about pull replication, the only difference being that the result of the search will be an array of the identifiers of the matching objects, not the objects themselves. In other words, the search will not cause any objects to become replicated.try {
IpIdentifier[] result =
IpSystem.searchObjectIds(destProcId,
pattern,
maxMatches,
timeout);
if (result == null) {
System.out.println(“Got 0 object identifiers”);
} else {
System.out.println(“Got ” + result.length + “ object ”
+
“identifiers”);
}
} catch (IpTimeoutException e) {
// timeout occured before any result was
returned
}
Object patterns are represented by instances of the IpObjectPattern class. After creating an empty pattern, it can be filled with requirements that distributed objects must fulfil in order to match the pattern.
There are tree different types of pattern requirements:
- Object identifier requirement
- Object class requirements
- Object property requirements
IpObjectPattern pattern = new
IpObjectPattern();
pattern.setId(id);
The class requirement can be used to search for distributed objects belonging to a specific class. There are actually two sub-types of class requirements, EQUALS and INSTANCEOF.
- If EQUALS is used, the class name of a distributed object must equal the pattern class name for the object to match the pattern
- If INSTANCEOF is used, the class of a distributed object must be an instance of the class identified by the pattern class name, where "instance of" has the same semantics as the Java instanceof operator.
/
/ Look for instances of the
GameObject class
pattern.setClass("GameObject", IpObjectPattern.EQUALS);
// Look for instances whose class extends the IpObject
// class, i.e., all distributed object classes
pattern.setClass("org.iperg.platform.core.IpObject", IpObjectPattern.INSTANCEOF);
Note that for class requirements to work, the receiving process needs to be able to find the classes corresponding to the class names in the class path. Therefore, it might be necessary to include path information in the class name given to setClass (for instance, as in the case of the IpObject class name above).
Property requirements allows the searching process to look for distributed objects whose properties have specific values.
// Look for distributed object that
has a
property named "age" in the
// default group and whose value is "5"
pattern.addProperty("age", "5");
Identifier, class and property requirements can of course be combined.
// Look for GameObject instances
whose age is 5 and whose speed is 4.0
pattern.setClass("GameObject",
IpObjectPattern.EQUALS);
pattern.addProperty("age", "5");
pattern.addProperty("group1", "speed", "4.0");
Object discoverability
When a distributed object copy is created, e.g., as a result of using new or a replication method, its status is such that it won't be discoverable via object searches. To make object discoverable, the setDiscoverable method should be used.// Create a distributed object
instance,
won't be discoverable
GameObject obj = new GameObject();
// Make it discoverable
obj.setDiscoverable(true);
Accessing remote process objects
As was mentioned in the Basics section of this manual, the local process is represented by an object, which is in fact a kind of a distributed object.IpProcess myProc =
IpSystem.getLocalProcess();
Since the IpProcess class is a sub-class of IpObject, all concepts such as properties, subscriptions, replication, etc. mentioned above are also valid for the process objects. For instance, a process could add some application specific properties to its local process object, providing information about the state of the process. Other processes could then replicate the process object, and possibly even subscribe to its properties, in order to access (and monitor) the state of the process.
Adding an application name to the process object can for instance be done like this:
myProc.addProperty("name",
"someApplicationName");
If we note that the identifier of the local process is in fact the identifier of the local process object, it's easy to retrieve the local process object from a remote process if we know the process identifier (since the identifiers are the same!). Identifiers of remote processes are for instance made available to the application code when network connections are established. This means that a running process will typically know the identity of at least a few other processes.
IpObjectPattern pattern = new
IpObjectPattern();
pattern.setId(procId); <= process id is really
object id!
try {
IpObject[] result =
IpSystem.searchObjects(procId,
pattern,
1,
timeout);
if (result != null) {
// got
process object
}
} catch (IpTimeoutException e) {
// timeout occured before any result was
returned
}
For instance, if we know that all applications have added a name property to their process objects, we can print these name like this:
System.out.println("The name of the
application is " + result[0].getProperty("name"));