Up to now, I had two message types: 1. a channel's message which was sent between two co-engaged Client Devices to let each other know that they are still interested in maintaining the engagement (one device has to send a channel message to the the second one before a cycle interval lapses, or the second assumes the first has lost interest in remaining engaged and hence destroys its channel) and 2. a subscriber's message which allows co-engaged Client Devices to communicate general state information. The second of these two message types had yet to be used.
I didn't like the channel's message. It separated the process of keeping channels open from the communication of state, and I didn't like this fact because the Client Device engagement is state information, and having the notion of engagement handled by a separate message was a complication that obstructed the implementation of an efficient way to relay state through a cluster of Client Devices. The channel's message was a good stop-gap way to get the Client Devices to work in a way that would be analogous to they way they would finally work while some of the background necessary to this final behaviour had yet to be developed. Now that the background has been developed, the time to remove the channel's message is upon me.
By removing the channel's message and using the subscriber's message for channel mechanics as well as general device state, I think I have come up with a near-final overall system for the representation and the communication of state. Hence, sate information as well as channel mechanics should now be handled by a single message - the subscriber message. Furthermore, the subscriber message can now be known merely as the message.
To make this feat possible, there is a very complicated structure and mechanism that culminates in the exchange of delegate Connection Limiting Constraint signals as the final part of the Client Device activation process. The channel of each of the two Client Devices currently in the process of engaging is finally activated when these signals are first exchanged, and continues until one of the devices detects that the other has not sent a signal before the channel's cycle interval lapses.
The code below, is a selective quote of the subscription's subscribe method. Limiting Constraints extend subscriptions, so this method applies to Limiting Constraints by virtue of this extension.
public final void subscribe(PostsynapticChannel channel,OutboundConnection subscriber)throws CliqueSpaceException{ /*Uninteresting code removed.*/ SynapseOwnerParticipant pIn=channel.getInboundSynapse().getOwner(); LimitingConstraint lcIn=pIn.getLimitingConstraint(ClientDeviceMediaProfile.DELEGATE_CONNECTION); boolean cycleIn=this==lcIn; SynapseOwnerParticipant pOut=channel.getOutboundSynapse().getOwner(); LimitingConstraint lcOut=pOut.getLimitingConstraint(ClientDeviceMediaProfile.DELEGATE_CONNECTION); boolean cycleOut=this==lcOut; OutboundConnection c=channel.getOutboundConnection(); this.subscribers.add(subscriber); if(cycleIn&&channel.isInitiator()||cycleOut&&channel.isRespondent()){ if(c!=subscriber){ throw new Subscribe_FirstCycleSubscriberNotOutboundConnection(); } /*Uninteresting code removed.*/ channel.activate(); }else if(cycleOut&&c==subscriber){ ChannelAdviser ca=channel.getChannelAdviser(); if(ca==null){ throw new Subscribe_ChannelAdviserDoesNotExist(); } int ci=channel.getDrive().getCycleInterval(); if(ci==0){ throw new Subscribe_CycleIntervalNotSet(); } try{ ca.join(ci); if(ca.isAlive()){ ca.interrupt(); throw new InterruptedException("Cycle interval exceeded; other Client Device is probably unresponsive."); } }catch(InterruptedException ex){ throw new Subscribe_CurrentAdviserHasBeenInterrupted(ex); } channel.getDrive().interrupt(); } }
The method starts by ascertaining whether this subscription is a delegate Connection's Limiting Constraint to the synapse Owner Participant of either the given channel's inbound or outbound synapse, and sets cycleIn or cycleOut to capture the result of this interrogation. Next, the given subscriber is added to the set of subscribers known to have expressed an interest in this subscription.
The if statement combines the values of the earlier defined flags with the role the host is playing in the engagement process to determine whether or not the channel needs to be activated. To clarify the necessity of requiring the channel's methods isInitiator and isRespondent, the following code snippet shows how these methods work.
public boolean isInitiator()throws CliqueSpaceException{ boolean isInitiator; if(this.isInitiator==null){ isInitiator=false; }else{ isInitiator=this.isInitiator; } return isInitiator; } public boolean isRespondent()throws CliqueSpaceException{ boolean isRespondent; if(this.isInitiator==null){ isRespondent=false; }else{ isRespondent=!this.isInitiator; } return isRespondent; }
When the two devices are engaging (before the channels have been activated) each device is assigned a role; the device that started the engagement process is known as the initiator and the device that is responding to the initiator's engagement request is known as the respondent. These methods will return true for a particular associated role while the two devices are in the process of engaging. They will return false regardless of which role a host took in the engagement process after the engagement process has finished (when the channel has been activated), and the two devices are merely cycling the delegate Connection's Limiting Constraint messages so to keep the channel open.
Hence, the if part in the first code snippet will only be executed once on each Client Device for a given engagement process. One observes the call to the given channel's activate method, a call that is made once only for each engagement. The activate method sets the channel's isInitiator field to null.
In the else if block of the fist code snippet, one can observe that the previous adviser thread (a thread which advises the co-engaged Client Device of this host's interest in keeping the channel open) is retrieved. The first adviser's thread is created and started in the given channel's activate method. The current thread only has to wait for the cycle interval to elapse before it moves on - waiting longer than this will be useless because the channel will have been closed, and one would want to prevent the possibility that a hanging adviser hangs the current thread. The channels's drive is a thread which sleeps for the cycle interval, and is reawaken either by the expiry of this time, or by interruption. In this case, the drive, which should still be waiting for the cycle interval to expire, is interrupted by the current thread as the final action of this else if block. This else if block implements the to and fro mechanism that keeps a channel open because the drive, when interrupted, sets off a small train of processes which results in the delegate Connection's Limiting Constraint of the channel's inbound synapse Owner Participant to be transmitted to the other Client Device.
The mechanism still requires perhaps a little more development. I do fear that there remain some cases that are not covered because, again, there remain many unexplored use-cases which would have a bearing on this mechanism. Even though perhaps I might think this mechanism could very well be a culminating result of eight years and about four months of development of a concept which is more than 12 years old, there is yet more deliberation to come though possibly this is a stand-out moment in time for the development of Clique Space(TM).
No comments:
Post a Comment