/*
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.jboss.com.sun.corba.se.impl.oa.poa;
import org.jboss.com.sun.corba.se.impl.orbutil.concurrent.CondVar;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.Action;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.ActionBase;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.FSM;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.FSMImpl;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.Guard;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.GuardBase;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.Input;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.InputImpl;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.State;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.StateEngine;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.StateEngineFactory;
import org.jboss.com.sun.corba.se.spi.orbutil.fsm.StateImpl;
/**
* AOMEntry represents a Servant or potential Servant in the ActiveObjectMap. It may be in several states to allow for
* long incarnate or etherealize operations. The methods on this class mostly represent input symbols to the state
* machine that controls the lifecycle of the entry. A library is used to build the state machine rather than the more
* usual state pattern so that the state machine transitions are explicitly visible.
*/
public class AOMEntry extends FSMImpl
{
private final Thread[] etherealizer; // The actual etherealize operation for this entry. It is represented as a
// Thread because the POA.deactivate_object never waits for the completion.
private final int[] counter; // single element holder for counter accessed in actions
private final CondVar wait; // accessed in actions
final POAImpl poa;
public static final State INVALID = new StateImpl("Invalid");
public static final State INCARN = new StateImpl("Incarnating")
{
public void postAction(FSM fsm)
{
AOMEntry entry = (AOMEntry) fsm;
entry.wait.broadcast();
}
};
public static final State VALID = new StateImpl("Valid");
public static final State ETHP = new StateImpl("EtherealizePending");
public static final State ETH = new StateImpl("Etherealizing")
{
public void preAction(FSM fsm)
{
AOMEntry entry = (AOMEntry) fsm;
Thread etherealizer = entry.etherealizer[0];
if (etherealizer != null)
etherealizer.start();
}
public void postAction(FSM fsm)
{
AOMEntry entry = (AOMEntry) fsm;
entry.wait.broadcast();
}
};
public static final State DESTROYED = new StateImpl("Destroyed");
static final Input START_ETH = new InputImpl("startEtherealize");
static final Input ETH_DONE = new InputImpl("etherealizeDone");
static final Input INC_DONE = new InputImpl("incarnateDone");
static final Input INC_FAIL = new InputImpl("incarnateFailure");
static final Input ACTIVATE = new InputImpl("activateObject");
static final Input ENTER = new InputImpl("enter");
static final Input EXIT = new InputImpl("exit");
private static Action incrementAction = new ActionBase("increment")
{
public void doIt(FSM fsm, Input in)
{
AOMEntry entry = (AOMEntry) fsm;
entry.counter[0]++;
}
};
private static Action decrementAction = new ActionBase("decrement")
{
public void doIt(FSM fsm, Input in)
{
AOMEntry entry = (AOMEntry) fsm;
if (entry.counter[0] > 0)
entry.counter[0]--;
else
throw entry.poa.lifecycleWrapper().aomEntryDecZero();
}
};
private static Action throwIllegalStateExceptionAction = new ActionBase("throwIllegalStateException")
{
public void doIt(FSM fsm, Input in)
{
throw new IllegalStateException("No transitions allowed from the DESTROYED state");
}
};
private static Guard waitGuard = new GuardBase("wait")
{
public Guard.Result evaluate(FSM fsm, Input in)
{
AOMEntry entry = (AOMEntry) fsm;
try
{
entry.wait.await();
}
catch (InterruptedException exc)
{
// XXX Log this
// NO-OP
}
return Guard.Result.DEFERED;
}
};
private static class CounterGuard extends GuardBase
{
private int value;
public CounterGuard(int value)
{
super("counter>" + value);
this.value = value;
}
public Guard.Result evaluate(FSM fsm, Input in)
{
AOMEntry entry = (AOMEntry) fsm;
return Guard.Result.convert(entry.counter[0] > value);
}
};
private static GuardBase greaterZeroGuard = new CounterGuard(0);
private static Guard zeroGuard = new Guard.Complement(greaterZeroGuard);
private static GuardBase greaterOneGuard = new CounterGuard(1);
private static Guard oneGuard = new Guard.Complement(greaterOneGuard);
private static StateEngine engine;
static
{
engine = StateEngineFactory.create();
// State, Input, Guard, Action, new State
engine.add(INVALID, ENTER, incrementAction, INCARN);
engine.add(INVALID, ACTIVATE, null, VALID);
engine.setDefault(INVALID);
engine.add(INCARN, ENTER, waitGuard, null, INCARN);
engine.add(INCARN, EXIT, null, INCARN);
engine.add(INCARN, START_ETH, waitGuard, null, INCARN);
engine.add(INCARN, INC_DONE, null, VALID);
engine.add(INCARN, INC_FAIL, decrementAction, INVALID);
engine.add(VALID, ENTER, incrementAction, VALID);
engine.add(VALID, EXIT, decrementAction, VALID);
engine.add(VALID, START_ETH, greaterZeroGuard, null, ETHP);
engine.add(VALID, START_ETH, zeroGuard, null, ETH);
engine.add(ETHP, ENTER, waitGuard, null, ETHP);
engine.add(ETHP, START_ETH, null, ETHP);
engine.add(ETHP, EXIT, greaterOneGuard, decrementAction, ETHP);
engine.add(ETHP, EXIT, oneGuard, decrementAction, ETH);
engine.add(ETH, START_ETH, null, ETH);
engine.add(ETH, ETH_DONE, null, DESTROYED);
engine.add(ETH, ENTER, waitGuard, null, ETH);
engine.setDefault(DESTROYED, throwIllegalStateExceptionAction, DESTROYED);
engine.done();
}
public AOMEntry(POAImpl poa)
{
super(engine, INVALID, (poa.getORB()).poaFSMDebugFlag);
this.poa = poa;
etherealizer = new Thread[1];
etherealizer[0] = null;
counter = new int[1];
counter[0] = 0;
wait = new CondVar(poa.poaMutex, (poa.getORB()).poaConcurrencyDebugFlag);
}
// Methods that drive the FSM: the real interface to this class Most just call the doIt method, but startEtherealize
// needs the etherealizer.
public void startEtherealize(Thread etherealizer)
{
this.etherealizer[0] = etherealizer;
doIt(START_ETH);
}
public void etherealizeComplete()
{
doIt(ETH_DONE);
}
public void incarnateComplete()
{
doIt(INC_DONE);
}
public void incarnateFailure()
{
doIt(INC_FAIL);
}
public void activateObject()
{
doIt(ACTIVATE);
}
public void enter()
{
doIt(ENTER);
}
public void exit()
{
doIt(EXIT);
}
}