2 * Copyright (c) 2004-2007 Sun Microsystems, Inc. All rights reserved.
4 * The Sun Project JXTA(TM) Software License
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * 3. The end-user documentation included with the redistribution, if any, must
17 * include the following acknowledgment: "This product includes software
18 * developed by Sun Microsystems, Inc. for JXTA(TM) technology."
19 * Alternately, this acknowledgment may appear in the software itself, if
20 * and wherever such third-party acknowledgments normally appear.
22 * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
23 * not be used to endorse or promote products derived from this software
24 * without prior written permission. For written permission, please contact
25 * Project JXTA at http://www.jxta.org.
27 * 5. Products derived from this software may not be called "JXTA", nor may
28 * "JXTA" appear in their name, without prior written permission of Sun.
30 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
32 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
33 * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
36 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
39 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 * JXTA is a registered trademark of Sun Microsystems, Inc. in the United
42 * States and other countries.
44 * Please see the license information page at :
45 * <http://www.jxta.org/project/www/license.html> for instructions on use of
46 * the license in source files.
48 * ====================================================================
50 * This software consists of voluntary contributions made by many individuals
51 * on behalf of Project JXTA. For more information on Project JXTA, please see
52 * http://www.jxta.org.
54 * This license is based on the BSD license adopted by the Apache Foundation.
56 package net.jxta.endpoint;
59 * The complete standard messenger life cycle state machine that all messengers
60 * must obey. Compliant messengers can be built by implementing and using this
61 * class as an engine to orchestrate discrete operations.
63 * In order to use this class, one must implement the various abstract Action
64 * methods, so that they trigger the required operations.
66 * Synchronization has to be externally provided and usually needs to extend
67 * around sections wider than just the invocation of this class' methods. For
68 * example, if the user of this class maintains a queue, the state of the queue
69 * must be kept consistent with the invocation of {@link #msgsEvent},
70 * {@link #saturatedEvent}, and {@link #idleEvent}, which all denote different
71 * states of that queue. It is suggested to use the instance of this class as
72 * the synchronization object.
74 public abstract class MessengerState {
76 // All the transition map setup is rather terse because java tends to make
77 // it extremely verbose. We do not want to end up with 1000 lines of code
78 // for what amounts to initializing a table.
80 // Below is a method reference. It permits putting "what to do" in a field.
81 // The {@code doIt()} method is given the target object because we want our
82 // entire transition table to be a static singleton. Otherwise it would cost
83 // too much initializing each instance of this class.
85 private interface Action {
86 public void doIt(MessengerState messengerState);
89 // Action method "pointers".
90 // The transition table is static. Otherwise it would cost too much initializing each instance of this class.
92 private final static Action Connect = new Action() {
93 public void doIt(MessengerState messengerState) {
94 messengerState.connectAction();
97 private final static Action Closein = new Action() {
98 public void doIt(MessengerState s) {
102 private final static Action Start = new Action() {
103 public void doIt(MessengerState s) {
107 private final static Action Closeout = new Action() {
108 public void doIt(MessengerState messengerState) {
109 messengerState.closeOutputAction();
112 private final static Action Failall = new Action() {
113 public void doIt(MessengerState messengerState) {
114 messengerState.failAllAction();
117 private final static Action Closeio = new Action() {
118 public void doIt(MessengerState s) {
119 s.closeInputAction();
120 s.closeOutputAction();
123 private final static Action Closefail = new Action() {
124 public void doIt(MessengerState messengerState) {
125 messengerState.closeInputAction();
126 messengerState.failAllAction();
129 private final static Action Nop = new Action() {
130 public void doIt(MessengerState messengerState) {
135 * The transition each event causes when in that state.
137 private static class State {
138 private final int number;
140 private State stResolve;
141 private Action acResolve;
143 private State stMsgs;
144 private Action acMsgs;
146 private State stSaturated;
147 private Action acSaturated;
149 private State stClose;
150 private Action acClose;
152 private State stShutdown;
153 private Action acShutdown;
158 private State stDown;
159 private Action acDown;
161 private State stIdle;
162 private Action acIdle;
164 State(int stateNum) {
168 void init(Object[] data) {
169 stResolve = (State) data[0];
170 acResolve = (Action) data[1];
171 stMsgs = (State) data[2];
172 acMsgs = (Action) data[3];
173 stSaturated = (State) data[4];
174 acSaturated = (Action) data[5];
175 stClose = (State) data[6];
176 acClose = (Action) data[7];
177 stShutdown = (State) data[8];
178 acShutdown = (Action) data[9];
179 stUp = (State) data[10];
180 acUp = (Action) data[11];
181 stDown = (State) data[12];
182 acDown = (Action) data[13];
183 stIdle = (State) data[14];
184 acIdle = (Action) data[15];
189 // All the states. (We put them together in a class essentially to simplify initialization).
190 private static class TransitionMap {
192 private final static State Unresolved = new State(Messenger.UNRESOLVED);
193 private final static State ResPending = new State(Messenger.RESOLPENDING);
194 private final static State Resolving = new State(Messenger.RESOLVING);
195 private final static State ResolSat = new State(Messenger.RESOLSATURATED);
196 private final static State Connected = new State(Messenger.CONNECTED);
197 private final static State Disconned = new State(Messenger.DISCONNECTED);
198 private final static State Reconning = new State(Messenger.RECONNECTING);
199 private final static State ReconSat = new State(Messenger.RECONSATURATED);
200 private final static State Sending = new State(Messenger.SENDING);
201 private final static State SendingSat = new State(Messenger.SENDINGSATURATED);
202 private final static State ResClosing = new State(Messenger.RESOLCLOSING);
203 private final static State ReconClosing = new State(Messenger.RECONCLOSING);
204 private final static State Closing = new State(Messenger.CLOSING);
205 private final static State Disconning = new State(Messenger.DISCONNECTING);
206 private final static State Unresable = new State(Messenger.UNRESOLVABLE);
207 private final static State Closed = new State(Messenger.CLOSED);
208 private final static State Broken = new State(Messenger.BROKEN);
210 // The states need to exist before init, because they refer to each other.
211 // We overwrite them in-place with the complete data.
213 private final static Object[][] INIT_TRANSITION_MAP = {
215 /* STATE resolve, msgs, saturated, close, shutdown, up, down, idle */
218 {Resolving, Connect, ResPending, Connect, ResolSat, Connect, Closed, Closein, Broken, Closein, Connected, Nop, Unresolved, Nop, Unresolved, Nop},
221 {ResPending, Nop, ResPending, Nop, ResolSat, Nop, ResClosing, Closein, Broken, Closefail, Sending, Start, Unresable, Closefail, Resolving, Nop},
224 {Resolving, Nop, ResPending, Nop, ResolSat, Nop, Closed, Closein, Broken, Closein, Connected, Nop, Unresable, Closein, Resolving, Nop},
227 {ResolSat, Nop, ResPending, Nop, ResolSat, Nop, ResClosing, Closein, Broken, Closefail, SendingSat, Start, Unresable, Closefail, Resolving, Nop},
230 {Connected, Nop, Sending, Start, SendingSat, Start, Closed, Closeio, Broken, Closeio, Connected, Nop, Disconned, Nop, Connected, Nop},
233 {Disconned, Nop, Reconning, Connect, ReconSat, Connect, Closed, Closein, Broken, Closein, Connected, Nop, Disconned, Nop, Disconned, Nop},
236 {Reconning, Nop, Reconning, Nop, ReconSat, Nop, ReconClosing, Closein, Broken, Closefail, Sending, Start, Broken, Closefail, Disconned, Nop},
239 {ReconSat, Nop, Reconning, Nop, ReconSat, Nop, ReconClosing, Closein, Broken, Closefail, SendingSat, Start, Broken, Closefail, Disconned, Nop},
242 {Sending, Nop, Sending, Nop, SendingSat, Nop, Closing, Closein, Disconning, Closeio, Sending, Nop, Reconning, Connect, Connected, Nop},
244 /* SENDINGSATURATED*/
245 {SendingSat, Nop, Sending, Nop, SendingSat, Nop, Closing, Closein, Disconning, Closeio, SendingSat, Nop, ReconSat, Connect, Connected, Nop},
248 {ResClosing, Nop, ResClosing, Nop, ResClosing, Nop, ResClosing, Nop, Broken, Failall, Closing, Start, Unresable, Failall, ResClosing, Nop},
251 {ReconClosing, Nop, ReconClosing, Nop, ReconClosing, Nop, ReconClosing, Nop, Broken, Failall, Closing, Start, Broken, Failall, ReconClosing, Nop},
254 {Closing, Nop, Closing, Nop, Closing, Nop, Closing, Nop, Disconning, Closeout, Closing, Nop, ReconClosing, Connect, Closed, Closeout},
257 {Disconning, Nop, Disconning, Nop, Disconning, Nop, Disconning, Nop, Disconning, Nop, Disconning, Nop, Broken, Failall, Broken, Nop},
260 {Unresable, Nop, Unresable, Nop, Unresable, Nop, Unresable, Nop, Unresable, Nop, Unresable, Closeout, Unresable, Nop, Unresable, Nop},
263 {Closed, Nop, Closed, Nop, Closed, Nop, Closed, Nop, Closed, Nop, Closed, Closeout, Closed, Nop, Closed, Nop},
266 {Broken, Nop, Broken, Nop, Broken, Nop, Broken, Nop, Broken, Nop, Broken, Closeout, Broken, Nop, Broken, Nop}
270 // install the transitions map in its proper place.
271 Unresolved.init(INIT_TRANSITION_MAP[0]);
272 ResPending.init(INIT_TRANSITION_MAP[1]);
273 Resolving.init(INIT_TRANSITION_MAP[2]);
274 ResolSat.init(INIT_TRANSITION_MAP[3]);
275 Connected.init(INIT_TRANSITION_MAP[4]);
276 Disconned.init(INIT_TRANSITION_MAP[5]);
277 Reconning.init(INIT_TRANSITION_MAP[6]);
278 ReconSat.init(INIT_TRANSITION_MAP[7]);
279 Sending.init(INIT_TRANSITION_MAP[8]);
280 SendingSat.init(INIT_TRANSITION_MAP[9]);
281 ResClosing.init(INIT_TRANSITION_MAP[10]);
282 ReconClosing.init(INIT_TRANSITION_MAP[11]);
283 Closing.init(INIT_TRANSITION_MAP[12]);
284 Disconning.init(INIT_TRANSITION_MAP[13]);
285 Unresable.init(INIT_TRANSITION_MAP[14]);
286 Closed.init(INIT_TRANSITION_MAP[15]);
287 Broken.init(INIT_TRANSITION_MAP[16]);
294 private volatile State state = null;
297 * Constructs a new messenger state machine.
299 * The transition map is static and we refer to it only to grab the first
300 * state. After that, states refer to each other. The only reason they are
301 * members in the map is so that we can make references during init.
303 * @param connected If <tt>true</tt>, the initial state is {@link Messenger#CONNECTED} otherwise {@link Messenger#UNRESOLVED}.
305 protected MessengerState(boolean connected) {
307 state = connected ? TransitionMap.Connected : TransitionMap.Unresolved;
311 * @return The current state.
313 public int getState() {
314 // getState is always just a peek. It needs no sync.
321 public void resolveEvent() {
322 Action a = state.acResolve;
324 state = state.stResolve;
331 public void msgsEvent() {
332 Action a = state.acMsgs;
334 state = state.stMsgs;
341 public void saturatedEvent() {
342 Action a = state.acSaturated;
344 state = state.stSaturated;
351 public void closeEvent() {
352 Action a = state.acClose;
354 state = state.stClose;
361 public void shutdownEvent() {
362 Action a = state.acShutdown;
364 state = state.stShutdown;
371 public void upEvent() {
372 Action a = state.acUp;
381 public void downEvent() {
382 Action a = state.acDown;
384 state = state.stDown;
391 public void idleEvent() {
392 Action a = state.acIdle;
394 state = state.stIdle;
399 * Actions they're always called in sequence by event methods.
401 * Actions must not call event methods in sequence.
405 * Try to make a connection. Called whenever transitioning from a state that neither needs nor has a connection to a state
406 * that needs a connection and does not have it. Call upEvent when successful, or downEvent when failed.
408 protected abstract void connectAction();
411 * Start sending. Called whenever transitioning to a state that has both a connection and messages to send from a state that
412 * lacked either attributes. So, will be called after sending stopped due to broken cnx or idle condition. Call downEvent
413 * when stopping due to broken or closed connection, call {@link #idleEvent} when no pending message is left.
415 protected abstract void startAction();
418 * Reject new messages from now on. Called whenever transitioning from a state that is {@link Messenger#USABLE} to a state
419 * that is not. No event expected once done.
421 protected abstract void closeInputAction();
424 * Drain pending messages, all failed. Called once output is down and there are still pending messages.
425 * Call {@link #idleEvent} when done, as a normal result of no pending messages being left.
427 protected abstract void failAllAction();
430 * Force close output. Called whenever the underlying connection is to be discarded and never to be needed again. That is
431 * either because orderly close has completed, or shutdown is in progress. No event expected once done, but this action
432 * <b>must</b> cause any sending in progress to stop eventually. The fact that the sending has stopped must be reported as
433 * usual: either with a {@link #downEvent}, if the output closure caused the sending process to fail, or with an {@link
434 * #idleEvent} if the sending of the last message could be sent successfully despite the attempt at interrupting it.
436 * Sending is said to be in progress if, and only if, the last call to startAction is more recent than the last call to
437 * {@link #idleEvent} or {@link #downEvent}.
439 * It is advisable to also cancel an ongoing connect action, but not mandatory. If a {@link #connectAction} later succeeds,
440 * then {@link #upEvent} <b>must</b> be called as usual. This will result in another call to {@link #closeOutputAction}.
442 protected abstract void closeOutputAction();