package scs.demos.philosopher.servant;
import java.util.Random;
import scs.core.ConnectionDescription;
import scs.core.IReceptacles;
import scs.core.IReceptaclesHelper;
import scs.core.InvalidName;
import scs.demos.philosopher.Fork;
import scs.demos.philosopher.ForkHelper;
import scs.demos.philosopher.Observer;
import scs.demos.philosopher.ObserverHelper;
import scs.demos.philosopher.PhilosopherPOA;
import scs.demos.philosopher.PhilosopherState;
import scs.demos.philosopher.StatusInfo;
public class PhilosopherServant extends PhilosopherPOA {
protected String name = null;
protected PhilosopherComponent philosopher = null;
protected PhilosopherThread phiThread;
protected IReceptacles leftHand = null;
protected IReceptacles rightHand = null;
protected IReceptacles infoReceptacle = null;
protected PhilosopherState state = PhilosopherState.THINKING;
protected StatusInfo statusInfo = new StatusInfo();
protected int hunger = 0;
protected boolean hasRightFork = false;
protected boolean hasLeftFork = false;
public PhilosopherServant(PhilosopherComponent philosopher)
{
this.philosopher = philosopher;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
*
*/
private class PhilosopherThread extends Thread {
private boolean stopped = false;
PhilosopherServant phi = null;
@Override
public void run() {
while( ! this.stopped ){
phi.update();
phi.notifyObservers();
phi.sleep();
}
}
public PhilosopherThread(PhilosopherServant servant)
{
super(servant.name);
phi = servant;
}
}
public boolean isHungry() {
return this.hunger > 3;
}
private void eatSome() {
this.hunger = this.hunger - 3;
if ( ! isHungry() )
{
this.hunger = 0;
}
}
private void releaseForks() {
//System.out.println(name + " droped forks.");
this.releaseLeftFork();
this.releaseRightFork();
this.notifyObservers();
}
private void getMoreHungry() {
this.hunger++;
}
private void avoidDeadlock() {
Random r = new Random(System.currentTimeMillis());
if( ( (this.hasLeftFork && ! this.hasRightFork )
|| (!this.hasLeftFork && this.hasRightFork ) )
&& r.nextBoolean() ) {
if( this.hasLeftFork ) {
this.releaseLeftFork();
}
else if( this.hasRightFork ) {
this.releaseRightFork();
}
this.notifyObservers();
}
}
private void update() {
if( this.hasLeftFork && this.hasRightFork ) {
if( this.isHungry() ) {
this.setState(PhilosopherState.EATING);
this.eatSome();
} else {
this.releaseForks();
this.setState(PhilosopherState.THINKING);
}
} else {
this.getMoreHungry();
if( this.hunger < 3 )
setState( PhilosopherState.THINKING );
else if( this.hunger < 10 )
setState(PhilosopherState.HUNGRY);
else if( this.hunger < 40 )
setState(PhilosopherState.STARVING);
else
setState(PhilosopherState.DEAD);
if( this.isHungry() ) {
if( this.tryGetFork("left") )
return;
if( this.tryGetFork("right") )
return;
this.avoidDeadlock();
}
}
/*
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
}
void sleep() {
Random r = new Random();
try {
Thread.sleep( 500 + Math.round( 2000 * r.nextFloat() ) );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boolean getRightFork()
{
if( this.hasRightFork )
return true;
Fork fork = null;
try {
fork = ForkHelper.narrow(rightHand.getConnections("right")[0].objref);
this.hasRightFork = fork.get();
} catch (InvalidName e) {
e.printStackTrace();
}
return this.hasRightFork;
}
boolean getLeftFork()
{
if( this.hasLeftFork )
return true;
Fork fork = null;
try {
fork = ForkHelper.narrow( leftHand.getConnections("left")[0].objref );
this.hasLeftFork = fork.get();
} catch (InvalidName e) {
e.printStackTrace();
}
return this.hasLeftFork;
}
boolean releaseLeftFork()
{
Fork fork = null;
try {
fork = ForkHelper.narrow( leftHand.getConnections("left")[0].objref );
} catch (InvalidName e) {
e.printStackTrace();
}
this.hasLeftFork = false;
return fork.release();
}
boolean releaseRightFork()
{
Fork fork = null;
try {
fork = ForkHelper.narrow(rightHand.getConnections("right")[0].objref);
} catch (InvalidName e) {
e.printStackTrace();
}
this.hasRightFork = false;
return fork.release();
}
public boolean start() {
rightHand = IReceptaclesHelper.narrow(philosopher.getFacetByName("right"));
leftHand = IReceptaclesHelper.narrow(philosopher.getFacetByName("left"));
infoReceptacle = IReceptaclesHelper.narrow(philosopher.getFacetByName("info"));
phiThread = new PhilosopherThread(this);
phiThread.start();
return true;
}
private boolean tryGetFork(String fork) {
boolean hasFork = fork.equals("left") ? this.hasLeftFork : this.hasRightFork;
if( !hasFork ) {
if( (fork.equals("left") && this.getLeftFork())
|| (fork.equals("right") && this.getRightFork()) ) {
//System.err.println( name + " got " + fork + " fork." );
this.notifyObservers();
return true;
}
}
return false;
}
private void setState( PhilosopherState st ) {
this.state = st;
//this.notifyObservers();
}
private void notifyObservers() {
statusInfo.name = this.name;
statusInfo.state = this.state;
statusInfo.has_left_fork = this.hasLeftFork;
statusInfo.has_right_fork = this.hasRightFork;
statusInfo.ticks_since_last_meal = this.hunger;
ConnectionDescription conns[];
try {
conns = infoReceptacle.getConnections("info");
for (int i = 0; i < conns.length; i++) {
Observer obs = ObserverHelper.narrow( conns[i].objref );
obs.push(statusInfo);
}
} catch (InvalidName e) {
e.printStackTrace();
}
}
}