/*
* Copyright 2017 Data Access Technologies, Inc.
*
* Licensed under the Academic Free License version 3.0
* (http://www.opensource.org/licenses/afl-3.0.php), except as stated
* in the file entitled Licensing-Information.
*/
package fUML.Semantics.CommonBehaviors.Communications;
import fUML.Debug;
import fUML.Semantics.Classes.Kernel.Reference;
import fUML.Semantics.Classes.Kernel.Value;
import fUML.Semantics.CommonBehaviors.BasicBehaviors.Execution;
import fUML.Semantics.CommonBehaviors.BasicBehaviors.ParameterValue;
import fUML.Semantics.CommonBehaviors.BasicBehaviors.ParameterValueList;
import fUML.Syntax.Classes.Kernel.Operation;
import fUML.Syntax.Classes.Kernel.Parameter;
import fUML.Syntax.Classes.Kernel.ParameterDirectionKind;
import fUML.Syntax.Classes.Kernel.ParameterList;
public class CallEventExecution extends Execution {
public boolean callerSuspended = false;
public boolean isCallerSuspended() {
// Check if the caller is still suspended.
// This is done in isolation from possible concurrent updates to this flag.
_beginIsolation();
boolean isSuspended = this.callerSuspended;
Debug.println("[isCallerSuspended] operation = " + this.getOperation().name +
", callerSuspended = " + isSuspended);
_endIsolation();
return isSuspended;
}
public void setCallerSuspended(boolean callerSuspended) {
// Set the caller suspended flag to the given value.
// This is done in isolation from possible concurrent queries to this flag.
_beginIsolation();
this.callerSuspended = callerSuspended;
Debug.println("[setCallerSuspended] operation = " + this.getOperation().name +
", callerSuspended = " + callerSuspended);
_endIsolation();
}
public void suspendCaller() {
// Suspend the caller until the caller is released.
while(this.isCallerSuspended()) {
this.wait_();
}
}
public void releaseCaller() {
// Release the caller, if suspended.
this.setCallerSuspended(false);
}
@Override
public void execute() {
// Make the call on the target object (which is the context of this execution)
// and suspend the caller until the call is completed.
// Note: The callerSuspended flag needs to be set before the call is made,
// in case the call is immediately handled and returned, even before the
// suspend loop is started.
this.setCallerSuspended(true);
this.makeCall();
this.suspendCaller();
}
public void makeCall() {
// Make the call on the target object (which is the context of this execution)
// by sending a call event occurrence. (Note that the call will never be
// completed if the target is not an active object, since then the object
// would then have no event pool in which the event occurrence could be placed.)
Reference reference = new Reference();
reference.referent = this.context;
this.createEventOccurrence().sendTo(reference);
}
public EventOccurrence createEventOccurrence() {
// Create a call event occurrence associated with this call event execution.
// (This operation may be overridden in subclasses to alter how the event
// occurrence is create, e.g., if it is necessary to wrap it.)
CallEventOccurrence eventOccurrence = new CallEventOccurrence();
eventOccurrence.execution = this;
return eventOccurrence;
}
public Operation getOperation() {
// Return the operation being called by this call event execution.
return ((CallEventBehavior)this.getBehavior()).operation;
}
public ParameterValueList getInputParameterValues(){
// Return input parameter values for this execution
ParameterValueList parameterValues = new ParameterValueList();
for(int i=0; i < this.parameterValues.size(); i++){
ParameterValue parameterValue = this.parameterValues.get(i);
if(parameterValue.parameter.direction == ParameterDirectionKind.in
| parameterValue.parameter.direction == ParameterDirectionKind.inout){
parameterValues.addValue(parameterValue);
}
}
return parameterValues;
}
public void setOutputParameterValues(ParameterValueList parameterValues) {
// Set the output parameter values for this execution.
ParameterList parameters = this.getBehavior().ownedParameter;
int i = 1;
int j = 1;
while (i <= parameters.size()) {
Parameter parameter = parameters.get(i-1);
if (parameter.direction == ParameterDirectionKind.inout |
parameter.direction == ParameterDirectionKind.out |
parameter.direction == ParameterDirectionKind.return_ ) {
ParameterValue parameterValue = parameterValues.get(j-1);
parameterValue.parameter = parameter;
this.setParameterValue(parameterValue);
j = j + 1;
}
i = i + 1;
}
}
@Override
public Value new_() {
// Create a new call event execution.
return new CallEventExecution();
}
@Override
public Value copy() {
// Create a new call event execution that is a copy of this execution, with the
// caller initially not suspended.
CallEventExecution copy = (CallEventExecution)super.copy();
copy.callerSuspended = false;
return copy;
}
public void wait_() {
// Wait for an indeterminate amount of time to allow other concurrent
// executions to proceed.
// [There is no further formal specification for this operation.]
Debug.println(!ExecutionQueue.step(), "[wait] Stuck!");
}
}