Cluster synchronization

By utilizing a synchronization server that accepts connections from a cluster a communication network is established. Any node from the cluster can then propagate messages and objects to other nodes or access shared information from the synchronization server.
	
public class DummyCache extends SynchronizedObject {
	@Override
	public String getNamespace() {
		return DummyCache.class.getName();
	}
	@Override
	public void receive(String cmd) {
		refresh(cmd);
	}
	public void updateEntry(String id) {
		send(id);
		refresh(id);
	}
	private void refresh(String id) {
		//refresh the entry id
	}
}
	
To synchronize a cache it simply extends the superclass SynchronizedObject. The cache will then be registered automatical and can send messages to instances of the same cache on the connected cluster. If local changes require the cache to refresh it's content it can notify other nodes to refresh their respective cache as well. Providing a solution to volatile content in caches.
When a cache entry is expensive to create, objects can be stored on the synchronization server. Requiering only one node to create the entry. By implementing a synchronization server, cluster can retrieve information from a common location. Allowing to rollout configurations automatical to your web application by connecting it to a synchronization server. This allows to manage configurations on a remote location whilest providing a local client.

reserveObject A dummy is created on the server for a specific ID. When other client's query the object it will be noted as existing but unavailable.
updateObject Creates an object on the server for a specific ID. When other client's query the object it will be noted as existing and available.
getObject Gets the object for a specific ID from the server. The wrapper RemoteObject holds information about it's state. If the object does not exists the payload will be null.
waitForObj Gets the object for a specific ID from the server. When the object is existing but not available at the moment this call will lock till the object is ready(or has been removed).
removeObject Removes an object for a specific ID from the server.
setTimeout Sets the timeout for an object on the server to a fixed amount of time. After the time expires the object is deleted.
setTimeoutAfterRequest Sets the timeout for an object on the server to an amount of time that is refreshed whenever the server sends the object to a client.
setDefaultTimeout Like setTimeout but the amount is taken from the synchronization servers default timeout.
setDefaultTimeoutAfterRequest Like setTimeoutAfterRequest but the amount is taken from the synchronization servers default timeout.
executeMethod Executes a method on a server object specified by an id, a method name and method arguments. The return value of the method is returned to the client.

The protocol for communicating between client and synchronization server feautures different types of requests. Reserve and update are used to initialize objects. getObject and waitForObj retrieve objects with the option to wait until a reserved object is updated. removeObject allows to manually discard objects, while the timeout types allow to set up an automatic behaviour. executeMethod allows to alter the object on the synchronization server or use the objects as service.

By utilizing remote method calls thread safe locks can be used. If a node wants to execute an exclusive action, it aquires a lock for the action and releases it afterwards. During the execution no other node can obtain the lock. This allows a safe implementation, without having to limit access to the action to a single node. If the lock is not available the program can wait for it to be freed or deny the action.

//singleton instance
SynchronizationObjManager manager = SynchronizationObjManager.instance();
//the lock for the flow
RemoteObject ro = manager.getObject(flowName);
//getting the current lockHolder
ro = manager.executeMethod(flowName, new RemoteMethod("getLockHolder",null));
if ( ro.unpack() == null ) {
	//lock is not held by anyone
	Object[] args = new Object[1];
	args[0] = clientId;
	ro = manager.executeMethod(flowName, new RemoteMethod("lockFor",args));
	if ( clientId.equals(ro.unpack()) ) {
		//client aquired the lock
		logger.info("Lock "+flowName+" activated.");
		//working with the lock
		...
		//releasing the lock
		ro = manager.executeMethod(flowName, new RemoteMethod("unlock",args));
		if ( Boolean.TRUE.equals(ro.unpack()) ) {
			//The lock can now be used by other clients
			logger.info("Lock "+flowName+" deactivated");
		} else {
			//Could only happen if the lock wasn't aquired correctly
			logger.info("Lock "+flowName+" could not be deactivated");
		}
	} else {
		//another client took the lock between checking and acquiring
		logger.info("Lock "+flowName+" could not be activated.");
	}
}

The sourcecode shows the full process of checking, acquiring and releasing locks.