/* * 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 com.sun.corba.se.impl.oa.poa ; import org.omg.CORBA.INTERNAL ; import com.sun.corba.se.spi.orb.ORB ; import com.sun.corba.se.spi.orbutil.fsm.Action ; import com.sun.corba.se.spi.orbutil.fsm.ActionBase ; import com.sun.corba.se.spi.orbutil.fsm.Guard ; import com.sun.corba.se.spi.orbutil.fsm.GuardBase ; import com.sun.corba.se.spi.orbutil.fsm.State ; import com.sun.corba.se.spi.orbutil.fsm.StateImpl ; import com.sun.corba.se.spi.orbutil.fsm.Input ; import com.sun.corba.se.spi.orbutil.fsm.InputImpl ; import com.sun.corba.se.spi.orbutil.fsm.FSM ; import com.sun.corba.se.spi.orbutil.fsm.FSMImpl ; import com.sun.corba.se.spi.orbutil.fsm.StateEngine ; import com.sun.corba.se.spi.orbutil.fsm.StateEngineFactory ; import com.sun.corba.se.impl.orbutil.concurrent.Mutex ; import com.sun.corba.se.impl.orbutil.concurrent.CondVar ; /** 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, ((ORB)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, ((ORB)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 ) ; } }