AOMEntry.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.corba.se.impl.oa.poa ;
27
28import org.omg.CORBA.INTERNAL ;
29
30import com.sun.corba.se.spi.orb.ORB ;
31
32import com.sun.corba.se.spi.orbutil.fsm.Action ;
33import com.sun.corba.se.spi.orbutil.fsm.ActionBase ;
34import com.sun.corba.se.spi.orbutil.fsm.Guard ;
35import com.sun.corba.se.spi.orbutil.fsm.GuardBase ;
36import com.sun.corba.se.spi.orbutil.fsm.State ;
37import com.sun.corba.se.spi.orbutil.fsm.StateImpl ;
38import com.sun.corba.se.spi.orbutil.fsm.Input ;
39import com.sun.corba.se.spi.orbutil.fsm.InputImpl ;
40import com.sun.corba.se.spi.orbutil.fsm.FSM ;
41import com.sun.corba.se.spi.orbutil.fsm.FSMImpl ;
42import com.sun.corba.se.spi.orbutil.fsm.StateEngine ;
43import com.sun.corba.se.spi.orbutil.fsm.StateEngineFactory ;
44
45import com.sun.corba.se.impl.orbutil.concurrent.Mutex ;
46import com.sun.corba.se.impl.orbutil.concurrent.CondVar ;
47
48import org.omg.CORBA.SystemException ;
49
50import org.omg.PortableServer.POAPackage.ObjectAlreadyActive ;
51
52/** AOMEntry represents a Servant or potential Servant in the ActiveObjectMap.
53* It may be in several states to allow for long incarnate or etherealize operations.
54* The methods on this class mostly represent input symbols to the state machine
55* that controls the lifecycle of the entry.  A library is used to build the state
56* machine rather than the more usual state pattern so that the state machine
57* transitions are explicitly visible.
58*/
59public class AOMEntry extends FSMImpl {
60    private final Thread[] etherealizer ;   // The actual etherealize operation
61                                            // for this entry.  It is
62                                            // represented as a Thread because
63                                            // the POA.deactivate_object never
64                                            // waits for the completion.
65    private final int[] counter ;           // single element holder for counter
66                                            // accessed in actions
67    private final CondVar wait ;            // accessed in actions
68
69    final POAImpl poa ;
70
71    public static final State INVALID = new StateImpl( "Invalid" ) ;
72    public static final State INCARN  = new StateImpl( "Incarnating" ) {
73        public void postAction( FSM fsm ) {
74            AOMEntry entry = (AOMEntry)fsm ;
75            entry.wait.broadcast() ;
76        }
77    };
78    public static final State VALID   = new StateImpl( "Valid" ) ;
79    public static final State ETHP    = new StateImpl( "EtherealizePending" ) ;
80    public static final State ETH     = new StateImpl( "Etherealizing" ) {
81        public void preAction( FSM fsm ) {
82            AOMEntry entry = (AOMEntry)fsm ;
83            Thread etherealizer = entry.etherealizer[0] ;
84            if (etherealizer != null)
85                etherealizer.start() ;
86        }
87
88        public void postAction( FSM fsm ) {
89            AOMEntry entry = (AOMEntry)fsm ;
90            entry.wait.broadcast() ;
91        }
92    };
93    public static final State DESTROYED = new StateImpl( "Destroyed" ) ;
94
95    static final Input START_ETH    = new InputImpl( "startEtherealize" ) ;
96    static final Input ETH_DONE     = new InputImpl( "etherealizeDone" ) ;
97    static final Input INC_DONE     = new InputImpl( "incarnateDone" ) ;
98    static final Input INC_FAIL     = new InputImpl( "incarnateFailure" ) ;
99    static final Input ACTIVATE     = new InputImpl( "activateObject" ) ;
100    static final Input ENTER        = new InputImpl( "enter" ) ;
101    static final Input EXIT         = new InputImpl( "exit" ) ;
102
103    private static Action incrementAction = new ActionBase( "increment" ) {
104        public void doIt( FSM fsm, Input in ) {
105            AOMEntry entry = (AOMEntry)fsm ;
106            entry.counter[0]++ ;
107        }
108    } ;
109
110    private static Action decrementAction = new ActionBase( "decrement" ) {
111        public void doIt( FSM fsm, Input in ) {
112            AOMEntry entry = (AOMEntry)fsm ;
113            if (entry.counter[0] > 0)
114                entry.counter[0]-- ;
115            else
116                throw entry.poa.lifecycleWrapper().aomEntryDecZero() ;
117        }
118    } ;
119
120    private static Action throwIllegalStateExceptionAction = new ActionBase(
121        "throwIllegalStateException" ) {
122        public void doIt( FSM fsm, Input in ) {
123            throw new IllegalStateException(
124                "No transitions allowed from the DESTROYED state" ) ;
125        }
126    } ;
127
128    private static Action oaaAction = new ActionBase( "throwObjectAlreadyActive" ) {
129         public void doIt( FSM fsm, Input in ) {
130             throw new RuntimeException( new ObjectAlreadyActive() ) ;
131         }
132    } ;
133
134    private static Guard waitGuard = new GuardBase( "wait" ) {
135        public Guard.Result evaluate( FSM fsm, Input in ) {
136            AOMEntry entry = (AOMEntry)fsm ;
137            try {
138                entry.wait.await() ;
139            } catch (InterruptedException exc) {
140                // XXX Log this
141                // NO-OP
142            }
143
144            return Guard.Result.DEFERED ;
145        }
146    } ;
147
148
149    private static class CounterGuard extends GuardBase {
150        private int value ;
151
152        public CounterGuard( int value )
153        {
154            super( "counter>" + value ) ;
155            this.value = value ;
156        }
157
158        public Guard.Result evaluate( FSM fsm, Input in )
159        {
160            AOMEntry entry = (AOMEntry)fsm ;
161            return Guard.Result.convert( entry.counter[0] > value ) ;
162        }
163    } ;
164
165    private static GuardBase greaterZeroGuard = new CounterGuard( 0 ) ;
166    private static Guard zeroGuard = new Guard.Complement( greaterZeroGuard ) ;
167    private static GuardBase greaterOneGuard = new CounterGuard( 1 ) ;
168    private static Guard oneGuard = new Guard.Complement( greaterOneGuard ) ;
169
170    private static StateEngine engine ;
171
172    static {
173        engine = StateEngineFactory.create() ;
174
175        //          State,   Input,     Guard,                  Action,             new State
176
177        engine.add( INVALID, ENTER,                             incrementAction,    INCARN      ) ;
178        engine.add( INVALID, ACTIVATE,                          null,               VALID       ) ;
179        engine.setDefault( INVALID ) ;
180
181        engine.add( INCARN,  ENTER,     waitGuard,              null,               INCARN      ) ;
182        engine.add( INCARN,  EXIT,                              null,               INCARN      ) ;
183        engine.add( INCARN,  START_ETH, waitGuard,              null,               INCARN      ) ;
184        engine.add( INCARN,  INC_DONE,                          null,               VALID       ) ;
185        engine.add( INCARN,  INC_FAIL,                          decrementAction,    INVALID     ) ;
186        engine.add( INCARN,  ACTIVATE,                          oaaAction,          INCARN      ) ;
187
188        engine.add( VALID,   ENTER,                             incrementAction,    VALID       ) ;
189        engine.add( VALID,   EXIT,                              decrementAction,    VALID       ) ;
190        engine.add( VALID,   START_ETH, greaterZeroGuard,       null,               ETHP        ) ;
191        engine.add( VALID,   START_ETH, zeroGuard,              null,               ETH         ) ;
192        engine.add( VALID,   ACTIVATE,                          oaaAction,          VALID       ) ;
193
194        engine.add( ETHP,    ENTER,     waitGuard,              null,               ETHP        ) ;
195        engine.add( ETHP,    START_ETH,                         null,               ETHP        ) ;
196        engine.add( ETHP,    EXIT,      greaterOneGuard,        decrementAction,    ETHP        ) ;
197        engine.add( ETHP,    EXIT,      oneGuard,               decrementAction,    ETH         ) ;
198        engine.add( ETHP,    ACTIVATE,                          oaaAction,          ETHP        ) ;
199
200        engine.add( ETH,     START_ETH,                         null,               ETH         ) ;
201        engine.add( ETH,     ETH_DONE,                          null,               DESTROYED   ) ;
202        engine.add( ETH,     ACTIVATE,                          oaaAction,          ETH         ) ;
203        engine.add( ETH,     ENTER,     waitGuard,              null,               ETH         ) ;
204
205        engine.setDefault( DESTROYED, throwIllegalStateExceptionAction, DESTROYED ) ;
206
207        engine.done() ;
208    }
209
210    public AOMEntry( POAImpl poa )
211    {
212        super( engine, INVALID, ((ORB)poa.getORB()).poaFSMDebugFlag ) ;
213        this.poa = poa ;
214        etherealizer = new Thread[1] ;
215        etherealizer[0] = null ;
216        counter = new int[1] ;
217        counter[0] = 0 ;
218        wait = new CondVar( poa.poaMutex,
219            ((ORB)poa.getORB()).poaConcurrencyDebugFlag ) ;
220    }
221
222    // Methods that drive the FSM: the real interface to this class
223    // Most just call the doIt method, but startEtherealize needs
224    // the etherealizer.
225    public void startEtherealize( Thread etherealizer )
226    {
227        this.etherealizer[0] = etherealizer ;
228        doIt( START_ETH ) ;
229    }
230
231    public void etherealizeComplete() { doIt( ETH_DONE ) ; }
232    public void incarnateComplete() { doIt( INC_DONE ) ; }
233    public void incarnateFailure() { doIt( INC_FAIL ) ; }
234    public void activateObject() throws ObjectAlreadyActive {
235         try {
236             doIt( ACTIVATE ) ;
237         } catch (RuntimeException exc) {
238             Throwable thr = exc.getCause() ;
239             if (thr instanceof ObjectAlreadyActive)
240                 throw (ObjectAlreadyActive)thr ;
241             else
242                 throw exc ;
243         }
244    }
245    public void enter() { doIt( ENTER ) ; }
246    public void exit() { doIt( EXIT ) ; }
247}
248