/***************************************************************************
* Copyright (C) by Fabrizio Montesi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
* For details about the authors of this software, see the AUTHORS file. *
***************************************************************************/
package jolie.process;
import java.io.IOException;
import java.net.URISyntaxException;
import jolie.ExecutionThread;
import jolie.Interpreter;
import jolie.lang.Constants;
import jolie.net.CommChannel;
import jolie.net.CommMessage;
import jolie.net.ports.OutputPort;
import jolie.runtime.ExitingException;
import jolie.runtime.FaultException;
import jolie.runtime.Value;
import jolie.runtime.VariablePath;
import jolie.runtime.expression.Expression;
import jolie.runtime.typing.RequestResponseTypeDescription;
import jolie.runtime.typing.Type;
import jolie.runtime.typing.TypeCheckingException;
public class SolicitResponseProcess implements Process
{
private final String operationId;
private final OutputPort outputPort;
private final VariablePath inputVarPath; // may be null
private final Expression outputExpression; // may be null
private final Process installProcess; // may be null
private final RequestResponseTypeDescription types;
public SolicitResponseProcess(
String operationId,
OutputPort outputPort,
Expression outputExpression,
VariablePath inputVarPath,
Process installProcess,
RequestResponseTypeDescription types
) {
this.operationId = operationId;
this.outputPort = outputPort;
this.outputExpression = outputExpression;
this.inputVarPath = inputVarPath;
this.installProcess = installProcess;
this.types = types;
}
public Process clone( TransformationReason reason )
{
return new SolicitResponseProcess(
operationId,
outputPort,
( outputExpression == null ) ? null : outputExpression.cloneExpression( reason ),
( inputVarPath == null ) ? null : (VariablePath)inputVarPath.cloneExpression( reason ),
( installProcess == null ) ? null : installProcess.clone( reason ),
types
);
}
private void log( String message )
{
Interpreter.getInstance().logInfo( "[SolicitResponse operation " + operationId + "@" + outputPort.id() + "]: " + message );
}
public void run()
throws FaultException
{
if ( ExecutionThread.currentThread().isKilled() ) {
return;
}
boolean verbose = Interpreter.getInstance().verbose();
CommChannel channel = null;
try {
CommMessage message =
CommMessage.createRequest(
operationId,
outputPort.getResourcePath(),
outputPort.getInterface().interfaceForOperation(operationId),
outputPort.id(),
( outputExpression == null ) ? Value.UNDEFINED_VALUE : outputExpression.evaluate()
);
if ( types.requestType() != null ) {
types.requestType().check( message.value() );
}
channel = outputPort.getCommChannel();
if ( verbose ) {
log( "sending request " + message.id() );
}
channel.send( message );
//channel.release(); TODO release channel if possible (i.e. it will not be closed)
if ( verbose ) {
log( "request " + message.id() + " sent" );
}
CommMessage response = null;
do {
response = channel.recvResponseFor( message );
} while( response == null );
if ( verbose ) {
log( "received response for request " + response.id() );
}
if ( inputVarPath != null ) {
inputVarPath.setValue( response.value() );
}
if ( response.isFault() ) {
Type faultType = types.getFaultType( response.fault().faultName() );
if ( faultType != null ) {
try {
faultType.check( response.fault().value() );
} catch( TypeCheckingException e ) {
throw new FaultException( Constants.TYPE_MISMATCH_FAULT_NAME, "Received fault " + response.fault().faultName() + " TypeMismatch (" + operationId + "@" + outputPort.id() + "): " + e.getMessage() );
}
}
throw response.fault();
} else {
if ( types.responseType() != null ) {
try {
types.responseType().check( response.value() );
} catch( TypeCheckingException e ) {
throw new FaultException( Constants.TYPE_MISMATCH_FAULT_NAME, "Received message TypeMismatch (" + operationId + "@" + outputPort.id() + "): " + e.getMessage() );
}
}
}
try {
installProcess.run();
} catch( ExitingException e ) { assert false; }
} catch( IOException e ) {
throw new FaultException( Constants.IO_EXCEPTION_FAULT_NAME, e );
} catch( URISyntaxException e ) {
Interpreter.getInstance().logSevere( e );
} catch( TypeCheckingException e ) {
throw new FaultException( Constants.TYPE_MISMATCH_FAULT_NAME, "Output message TypeMismatch (" + operationId + "@" + outputPort.id() + "): " + e.getMessage() );
} finally {
if ( channel != null ) {
try {
channel.release();
} catch( IOException e ) {
Interpreter.getInstance().logWarning( e );
}
}
}
}
public boolean isKillable()
{
return true;
}
}