public final class Control
extends java.lang.Object
Object.wait()
) will
process accordingly (e.g. throw an InterruptedException
).
Any interruption that occurs during remote processing is delivered
to the other end of the session asynchronous to the "conversation". In
other words, this is an "out of band" notification attempt. As long as
processing is still local to the other side, the interruption will be
raised there, as a local exception. Any failure to deliver the
interruption on the remote side (e.g. the remote side called back to this
local side before the interruption could be delivered) will cause the
interruption to be honored at the moment that this side next shifts into
local processing mode.
This class maintains a stack of thread objects so that the current thread of execution on the local side is known. This is only used when processing is local.
Initially the stack is empty. The first call to the init(com.goldencode.p2j.net.Session)
method
implicitly pushes the first thread into the stack.
The current point of execution for the conversation is tracked between the remote side and the local side. Local execution is active in the following cases:
init()
.
pushRemoteCall(int)
and after the
corresponding call to popRemoteCall()
. These calls
form a "bracket" around remote processing.
pushUnconditionally(int)
and before the correspondng call to popUnconditionally()
,
processing is local.
To notify this class that an interruption needs to be delivered, use
interrupt()
.
Modifier and Type | Class and Description |
---|---|
private static class |
Control.Operation
Container for the current executed operation and its type.
|
Modifier and Type | Field and Description |
---|---|
private boolean |
async
true if currently processing an asynchronous signal. |
private static Control |
clientInstance
The generating side for asynchronous interruptions if non-null.
|
private java.util.Stack<java.lang.Thread> |
control
The control stack.
|
private boolean |
interrupted
true if an interruption signal has occurred. |
private Control |
leftSideControl
The Control instance for the session on the left-side of this Control.
|
private boolean |
local
Which side owns control now: local (true) or remote (false).
|
private java.lang.Thread |
lock
Global lock owner or
null if not locked. |
private static java.util.logging.Logger |
LOG
Logger
|
private java.util.Stack<Control.Operation> |
operations
The currently ongoing operations (requests or replies).
|
private boolean |
ready
Initialized flag.
|
private Control.Operation |
remoteOperation
The operation being processed on the other peer.
|
private java.util.Set<java.lang.Integer> |
remotePendingReplies
List of remote outstanding reply ids.
|
private Control |
rightSideControl
The Control instance for the session on the right-side of this Control.
|
private static ContextLocal<Control> |
serverInstance
The receiving side of asynchronous interruptions if non-null.
|
private Session |
session
The connection for this P2J session.
|
Modifier | Constructor and Description |
---|---|
private |
Control()
Constructor with restricted access (disallows external construction).
|
Modifier and Type | Method and Description |
---|---|
static void |
clearInterrupted()
Clears the pending interrupt flag.
|
(package private) void |
clearRemoteOperation()
Clear the data about the remote operation.
|
(package private) Control |
getRightSideControl()
Get the right-side instance for this virtual control.
|
(package private) static Session |
getSession(int contextID)
Get the session for the specified context.
|
(package private) java.lang.Thread |
getTargetThread()
Gets the currently executing thread without popping it off the stack.
|
(package private) static void |
handleInterrupted(java.lang.InterruptedException exc)
Trigger a notification when the thread is interrupted so that the
handler may take any action deemed appropriate like throwing a
customized exception.
|
private void |
handleInterruptedImpl(java.lang.InterruptedException exc)
Trigger a notification when the thread is interrupted so that the
handler may take any action deemed appropriate like throwing a
customized exception.
|
static void |
init(Session session)
Initializes the control stack.
|
(package private) void |
initControl(Session session)
Initializes the control stack.
|
static boolean |
interrupt()
Interrupts the execution of the conversation as the result of an
asynchronous interruption notification (usually by an end-user).
|
(package private) boolean |
interruptImpl(boolean rightSide)
Interrupts the execution of the conversation as the result of an
asynchronous interruption notification (usually by an end-user).
|
(package private) boolean |
isReady()
Return the
ready state of this control. |
(package private) static Control |
locate(int contextID)
Gets the instance of this class for the current context.
|
(package private) void |
lock()
Obtain the global lock on the session's instance.
|
private void |
lockCore()
Obtains the global lock, blocking until it is available.
|
private void |
popOperation()
Pop the operation stack.
|
(package private) void |
popRemoteCall()
Switches control back to the local side.
|
(package private) void |
popUnconditionally()
Unconditionally pops the current thread off the stack.
|
private void |
pushOperation(boolean request,
int operationId)
Push a new operation to the stack, saving its type and its ID.
|
(package private) void |
pushRemoteCall(int request)
Switches control to the remote side.
|
(package private) void |
pushUnconditionally(int request)
Unconditionally pushes the current thread onto the stack.
|
(package private) static void |
setContext(Control control)
Set the server instance for the current context.
|
(package private) void |
setLeftSideControl(Control control)
Set the left-side control for this virtual control, in the connection
chain.
|
(package private) void |
setRemoteOperation(boolean request,
int operationId,
int[] pendingReplies)
Save the state of the peer.
|
(package private) void |
setRightSideControl(Control control)
Set the right-side instance for this virtual control.
|
private boolean |
tryLock(java.lang.Thread thread)
Obtains the lock for the given thread if the lock is unowned, or if
owned, checks if the given thread owns the lock.
|
(package private) void |
unlock()
Release the global lock on the session's instance.
|
private void |
unlockCore()
Unlocks the global lock.
|
private static final java.util.logging.Logger LOG
private static Control clientInstance
private static ContextLocal<Control> serverInstance
private final java.util.Stack<Control.Operation> operations
private final java.util.Set<java.lang.Integer> remotePendingReplies
private Control.Operation remoteOperation
private boolean ready
private Session session
private boolean local
private boolean interrupted
true
if an interruption signal has occurred.private boolean async
true
if currently processing an asynchronous signal.private java.util.Stack<java.lang.Thread> control
private java.lang.Thread lock
null
if not locked.private Control leftSideControl
rightSideControl
must be null.private Control rightSideControl
leftSideControl
must be null.private Control()
public static void init(Session session)
session
- The connection for this context.void initControl(Session session)
session
- The connection for this context.public static void clearInterrupted()
InterruptedException
is caught to avoid duplicate
exceptions.public static boolean interrupt()
Since this call is made on a different thread, the target thread has to be interrupted.
If by the time this call is made control is with the remote side AND the original interrupt request was generated on this node, a remote call is made to interrupt the conversation there.
true
if the interrupt request was successfully
delivered.boolean interruptImpl(boolean rightSide)
Since this call is made on a different thread, the target thread has to be interrupted.
If by the time this call is made control is with the remote side AND the original interrupt request was generated on this node, a remote call is made to interrupt the conversation there.
rightSide
- true
if the interruption is delivered to the
right-side relative to the control for the current context.true
if the interrupt request was successfully
delivered.static Session getSession(int contextID)
contextID
- The context to which the interruption must be applied.boolean isReady()
ready
state of this control.true
if this control is ready
.void setRemoteOperation(boolean request, int operationId, int[] pendingReplies)
request
- The remote operation type. true
for request.operationId
- The remote operation ID.pendingReplies
- The list of remote outstanding replies.void clearRemoteOperation()
private void pushOperation(boolean request, int operationId)
request
- true
if this is a requests, false
for
a replyoperationId
- the ID of the current operation being executed.private void popOperation()
void lock()
unlock()
.void unlock()
void pushRemoteCall(int request)
interrupt()
has been issued but not yet honored), then this
method calls handleInterrupted()
.
This method will block until it can obtain the global lock on this instance. Before returning, that lock will be released.
If this instance is in asynchronous notification mode, then this method is a NOP. Otherwise the state of the instance would change during the asynchronous notification, which would be improper since such notifications are by nature supposed to be "out of band". Thus state changes for the normal communication channels must be unaffected.
request
- the ID of the current request being executed.void popRemoteCall()
interrupt()
has been issued but not yet honored), then this
method calls handleInterrupted()
.
This method will block until it can obtain the global lock on this instance. Before returning, that lock will be released.
If this instance is in asynchronous notification mode, then this method is a NOP. Otherwise the state of the instance would change during the asynchronous notification, which would be improper since such notifications are by nature supposed to be "out of band". Thus state changes for the normal communication channels must be unaffected.
void pushUnconditionally(int request)
This method will block until it can obtain the global lock on this instance. Before returning, that lock will be released.
MUST NOT be called from any thread used for an asynchronous
notification, such as the one generated by interrupt()
to
trigger a remote interruption.
request
- the ID of the request being processed.void popUnconditionally()
This method will block until it can obtain the global lock on this instance. Before returning, that lock will be released.
MUST NOT be called from any thread used for an asynchronous
notification, such as the one generated by interrupt()
to
trigger a remote interruption.
java.lang.Thread getTargetThread()
null
if control is on the
remote side.void setLeftSideControl(Control control)
control
- the left-side instance, which transferes control to the virtual
sessionvoid setRightSideControl(Control control)
control
- the right-side instance, which transfered control to usControl getRightSideControl()
private boolean tryLock(java.lang.Thread thread)
thread
- The potential owner.true
if the thread owns the lock (by obtaining
it within this method or by having previously obtained it).
false
if some other thread owns the lock.private void lockCore()
private void unlockCore()
static void handleInterrupted(java.lang.InterruptedException exc)
exc
- The original InterruptedException
.private void handleInterruptedImpl(java.lang.InterruptedException exc)
exc
- The original InterruptedException
.static Control locate(int contextID)
When the passed context ID is 0, it means it must retrieve either the
control for the client instance or the registered control for the current
context, if clientInstance
is null.
contextID
- The context for which the control instance must be located.static void setContext(Control control)
control
- Object used as the server instance.