/***************************************************************************
* Copyright (C) 2006-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.process;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import jolie.ExecutionThread;
import jolie.Interpreter;
import jolie.net.SessionMessage;
import jolie.runtime.ExitingException;
import jolie.runtime.FaultException;
import jolie.runtime.InputOperation;
import jolie.util.Pair;
/** Implements a non-deterministic choice.
* An NDChoiceProcess instance collects pairs which couple an
* InputOperationProcess object with a Process object.
* When the ChoiceProcess object is run, it waits for
* the receiving of a communication on one of its InputProcess objects.
* When a communication is received, the following happens:
* \li the communication is resolved by the corresponding InputProcess instance.
* \li the paired Process object is executed.
*
* After that, the ChoiceProcess terminates, so the other pairs are ignored.
*
* @author Fabrizio Montesi
*/
public class NDChoiceProcess implements Process
{
private Map< String, Pair< InputOperationProcess, Process > > branches =
new HashMap< String, Pair< InputOperationProcess, Process > >();
private final InputOperation[] inputOperations;
private Map< String, InputOperation > inputOperationsMap =
new HashMap< String, InputOperation >();
/** Constructor */
public NDChoiceProcess( Pair< InputOperationProcess, Process >[] branches )
{
inputOperations = new InputOperation[ branches.length ];
int i = 0;
for( Pair< InputOperationProcess, Process > pair : branches ) {
inputOperations[ i++ ] = pair.key().inputOperation();
this.branches.put( pair.key().inputOperation().id(), pair );
this.inputOperationsMap.put( pair.key().inputOperation().id(), pair.key().inputOperation() );
}
this.branches = Collections.unmodifiableMap( this.branches );
this.inputOperationsMap = Collections.unmodifiableMap( this.inputOperationsMap );
}
public Process clone( TransformationReason reason )
{
Pair< InputOperationProcess, Process >[] b = new Pair[ branches.values().size() ];
int i = 0;
for( Pair< InputOperationProcess, Process > pair : branches.values() ) {
b[ i++ ] = new Pair< InputOperationProcess, Process >( pair.key(), pair.value().clone( reason ) );
}
return new NDChoiceProcess( b );
}
/** Runs the non-deterministic choice behaviour. */
public void run()
throws FaultException, ExitingException
{
ExecutionThread ethread = ExecutionThread.currentThread();
if ( ethread.isKilled() ) {
return;
}
Future< SessionMessage > f = ethread.requestMessage( inputOperationsMap, ethread );
try {
SessionMessage m = f.get();
Pair< InputOperationProcess, Process > branch = branches.get( m.message().operationName() );
branch.key().receiveMessage( m, ethread.state() ).run();
branch.value().run();
} catch( CancellationException e ) {
Interpreter.getInstance().logSevere( e );
} catch( ExecutionException e ) {
Interpreter.getInstance().logSevere( e );
} catch( InterruptedException e ) {
Interpreter.getInstance().logSevere( e );
}
}
public boolean isKillable()
{
return true;
}
}