/***************************************************************************
* Copyright (C) 2009-2011 by Fabrizio Montesi <famontesi@gmail.com> *
* *
* 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.net;
import java.io.IOException;
import java.net.URISyntaxException;
import jolie.ExecutionThread;
import jolie.Interpreter;
import jolie.SessionListener;
import jolie.SessionThread;
import jolie.State;
import jolie.lang.Constants;
import jolie.lang.Constants.OperationType;
import jolie.net.ports.OutputPort;
import jolie.process.OneWayProcess;
import jolie.runtime.FaultException;
import jolie.runtime.VariablePath;
import jolie.process.Process;
import jolie.process.RequestResponseProcess;
import jolie.process.SequentialProcess;
import jolie.runtime.OneWayOperation;
import jolie.runtime.RequestResponseOperation;
import jolie.runtime.typing.TypeCheckingException;
/**
* An AggregatedOperation instance contains information about an operation that is aggregated by an input port.
* @author Fabrizio Montesi
*/
public abstract class AggregatedOperation
{
private static class CourierOneWayAggregatedOperation extends AggregatedOperation {
private final OneWayOperation operation;
private final Process courierProcess;
private final VariablePath inputVariablePath;
public CourierOneWayAggregatedOperation(
OneWayOperation operation,
VariablePath inputVariablePath,
Process courierProcess
) {
super( operation.id() );
this.operation = operation;
this.inputVariablePath = inputVariablePath;
this.courierProcess = courierProcess;
}
public OperationType type()
{
return OperationType.ONE_WAY;
}
public void runAggregationBehaviour( final CommMessage requestMessage, final CommChannel channel )
throws IOException, URISyntaxException
{
Interpreter interpreter = Interpreter.getInstance();
try {
operation.requestType().check( requestMessage.value() );
ExecutionThread initThread = Interpreter.getInstance().initThread();
try {
initThread.join();
} catch( InterruptedException e ) {
throw new IOException( e );
}
State state = initThread.state().clone();
Process p = new SequentialProcess( new Process[] {
new OneWayProcess( operation, inputVariablePath ).receiveMessage( new SessionMessage( requestMessage, channel ), state ),
courierProcess
});
SessionThread t = new SessionThread( p, state, initThread );
final FaultException[] f = new FaultException[1];
f[0] = null;
t.addSessionListener( new SessionListener() {
public void onSessionExecuted( SessionThread session )
{}
public void onSessionError( SessionThread session, FaultException fault )
{
// We need to send the acknowledgement
if ( fault.faultName().equals( "CorrelationError" )
|| fault.faultName().equals( "IOException" )
|| fault.faultName().equals( "TypeMismatch" )
) {
synchronized( f ) {
f[0] = fault;
}
} else {
Interpreter.getInstance().logSevere( "Courier session for operation " + operation.id() + " has thrown fault " + fault.faultName() + ", which cannot be forwarded to the caller. Forwarding IOException." );
synchronized( f ) {
f[0] = new FaultException( jolie.lang.Constants.IO_EXCEPTION_FAULT_NAME, fault.faultName() );
}
}
}
} );
t.start();
try {
t.join();
} catch( InterruptedException e ) {}
synchronized( f ) {
if ( f[0] == null ) {
// We need to send the acknowledgement
channel.send( CommMessage.createEmptyResponse( requestMessage ) );
} else {
channel.send( CommMessage.createFaultResponse( requestMessage, f[0] ) );
}
}
} catch( TypeCheckingException e ) {
interpreter.logWarning( "TypeMismatch for received message (input operation " + operation.id() + "): " + e.getMessage() );
try {
channel.send( CommMessage.createFaultResponse( requestMessage, new FaultException( jolie.lang.Constants.TYPE_MISMATCH_FAULT_NAME, e.getMessage() ) ) );
} catch( IOException ioe ) {
Interpreter.getInstance().logSevere( ioe );
}
} finally {
channel.disposeForInput();
}
}
}
private static class CourierRequestResponseAggregatedOperation extends AggregatedOperation {
private final RequestResponseOperation operation;
private final Process courierProcess;
private final VariablePath inputVariablePath;
private final VariablePath outputVariablePath;
public CourierRequestResponseAggregatedOperation(
RequestResponseOperation operation,
VariablePath inputVariablePath,
VariablePath outputVariablePath,
Process courierProcess
) {
super( operation.id() );
this.operation = operation;
this.inputVariablePath = inputVariablePath;
this.outputVariablePath = outputVariablePath;
this.courierProcess = courierProcess;
}
public OperationType type()
{
return OperationType.REQUEST_RESPONSE;
}
public void runAggregationBehaviour( final CommMessage requestMessage, final CommChannel channel )
throws IOException, URISyntaxException
{
Interpreter interpreter = Interpreter.getInstance();
try {
operation.requestType().check( requestMessage.value() );
ExecutionThread initThread = Interpreter.getInstance().initThread();
try {
initThread.join();
} catch( InterruptedException e ) {
throw new IOException( e );
}
State state = initThread.state().clone();
Process p = new RequestResponseProcess( operation, inputVariablePath, outputVariablePath, courierProcess )
.receiveMessage( new SessionMessage( requestMessage, channel ), state );
new SessionThread( p, state, initThread ).start();
} catch( TypeCheckingException e ) {
interpreter.logWarning( "Received message TypeMismatch (input operation " + operation.id() + "): " + e.getMessage() );
try {
channel.send( CommMessage.createFaultResponse( requestMessage, new FaultException( jolie.lang.Constants.TYPE_MISMATCH_FAULT_NAME, e.getMessage() ) ) );
} catch( IOException ioe ) {
Interpreter.getInstance().logSevere( ioe );
}
} finally {
channel.disposeForInput();
}
}
}
private static class DirectAggregatedOperation extends AggregatedOperation {
private final OutputPort outputPort;
private final Constants.OperationType type;
public DirectAggregatedOperation( String name, Constants.OperationType type, OutputPort outputPort )
{
super( name );
this.type = type;
this.outputPort = outputPort;
}
public OperationType type()
{
return type;
}
public void runAggregationBehaviour( CommMessage requestMessage, CommChannel channel )
throws IOException, URISyntaxException
{
// Aggregation input
/*if ( type == OperationType.ONE_WAY ) {
CommChannel oChannel = outputPort.getCommChannel();
oChannel.send( requestMessage );
oChannel.release();
} else {*/
CommChannel oChannel = outputPort.getNewCommChannel();
oChannel.setRedirectionChannel( channel );
oChannel.setRedirectionMessageId( requestMessage.id() );
try {
oChannel.send( outputPort.getResourceUpdatedMessage( requestMessage ) );
oChannel.setToBeClosed( false );
oChannel.disposeForInput();
} catch( IOException e ) {
channel.send( CommMessage.createFaultResponse( requestMessage, new FaultException( e ) ) );
channel.disposeForInput();
}
//}
}
}
private final String name;
private AggregatedOperation( String name )
{
this.name = name;
}
public static AggregatedOperation createDirect( String name, Constants.OperationType type, OutputPort outputPort )
{
return new DirectAggregatedOperation( name, type, outputPort );
}
public static AggregatedOperation createWithCourier(
OneWayOperation operation,
VariablePath inputVariablePath,
Process courierProcess
) {
return new CourierOneWayAggregatedOperation( operation, inputVariablePath, courierProcess );
}
public static AggregatedOperation createWithCourier(
RequestResponseOperation operation,
VariablePath inputVariablePath,
VariablePath outputVariablePath,
Process courierProcess
) {
return new CourierRequestResponseAggregatedOperation( operation, inputVariablePath, outputVariablePath, courierProcess );
}
/**
* Returns the operation type of this operation
* @return the operation type of this operation
* @see OperationType
*/
public abstract OperationType type();
/**
* Returns the name of this operation.
* @return the name of this operation.
*/
public String name()
{
return name;
}
public abstract void runAggregationBehaviour( CommMessage requestMessage, CommChannel channel )
throws IOException, URISyntaxException;
}