]> sjero.net Git - linphone/blob - p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/endpoint/MessengerState.java
df7c1cd6a1325ec903f8d1f6663aa745435dd0f6
[linphone] / p2pproxy / dependencies-src / jxse-src-2.5 / api / src / net / jxta / endpoint / MessengerState.java
1 /*
2  * Copyright (c) 2004-2007 Sun Microsystems, Inc.  All rights reserved.
3  *  
4  *  The Sun Project JXTA(TM) Software License
5  *  
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions are met:
8  *  
9  *  1. Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *  
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.
15  *  
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.
21  *  
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.
26  *  
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.
29  *  
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.
40  *  
41  *  JXTA is a registered trademark of Sun Microsystems, Inc. in the United 
42  *  States and other countries.
43  *  
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.
47  *  
48  *  ====================================================================
49  *  
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.
53  *  
54  *  This license is based on the BSD license adopted by the Apache Foundation. 
55  */
56 package net.jxta.endpoint;
57
58 /**
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.
62  * <p/>
63  * In order to use this class, one must implement the various abstract Action
64  * methods, so that they trigger the required operations.
65  * <p/>
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.
73  */
74 public abstract class MessengerState {
75
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.
79
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.
84
85     private interface Action {
86         public void doIt(MessengerState messengerState);
87     }
88
89     // Action method "pointers".
90     // The transition table is static. Otherwise it would cost too much initializing each instance of this class.
91
92     private final static Action Connect = new Action() {
93         public void doIt(MessengerState messengerState) {
94             messengerState.connectAction();
95         }
96     };
97     private final static Action Closein = new Action() {
98         public void doIt(MessengerState s) {
99             s.closeInputAction();
100         }
101     };
102     private final static Action Start = new Action() {
103         public void doIt(MessengerState s) {
104             s.startAction();
105         }
106     };
107     private final static Action Closeout = new Action() {
108         public void doIt(MessengerState messengerState) {
109             messengerState.closeOutputAction();
110         }
111     };
112     private final static Action Failall = new Action() {
113         public void doIt(MessengerState messengerState) {
114             messengerState.failAllAction();
115         }
116     };
117     private final static Action Closeio = new Action() {
118         public void doIt(MessengerState s) {
119             s.closeInputAction();
120             s.closeOutputAction();
121         }
122     };
123     private final static Action Closefail = new Action() {
124         public void doIt(MessengerState messengerState) {
125             messengerState.closeInputAction();
126             messengerState.failAllAction();
127         }
128     };
129     private final static Action Nop = new Action() {
130         public void doIt(MessengerState messengerState) {
131         }
132     };
133
134     /**
135      * The transition each event causes when in that state.
136      */
137     private static class State {
138         private final int number;
139
140         private State stResolve;
141         private Action acResolve;
142
143         private State stMsgs;
144         private Action acMsgs;
145
146         private State stSaturated;
147         private Action acSaturated;
148
149         private State stClose;
150         private Action acClose;
151
152         private State stShutdown;
153         private Action acShutdown;
154
155         private State stUp;
156         private Action acUp;
157
158         private State stDown;
159         private Action acDown;
160
161         private State stIdle;
162         private Action acIdle;
163
164         State(int stateNum) {
165             number = stateNum;
166         }
167
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];
185         }
186     }
187
188
189     // All the states. (We put them together in a class essentially to simplify initialization).
190     private static class TransitionMap {
191
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);
209
210         // The states need to exist before init, because they refer to each other.
211         // We overwrite them in-place with the complete data.
212
213         private final static Object[][] INIT_TRANSITION_MAP = {
214
215                 /* STATE resolve, msgs, saturated, close, shutdown, up, down, idle */
216
217                 /* UNRESOLVED      */
218                 {Resolving, Connect, ResPending, Connect, ResolSat, Connect, Closed, Closein, Broken, Closein, Connected, Nop, Unresolved, Nop, Unresolved, Nop},
219
220                 /* RESOLPENDING    */
221                 {ResPending, Nop, ResPending, Nop, ResolSat, Nop, ResClosing, Closein, Broken, Closefail, Sending, Start, Unresable, Closefail, Resolving, Nop},
222
223                 /* RESOLVING       */
224                 {Resolving, Nop, ResPending, Nop, ResolSat, Nop, Closed, Closein, Broken, Closein, Connected, Nop, Unresable, Closein, Resolving, Nop},
225
226                 /* RESOLSATURATED  */
227                 {ResolSat, Nop, ResPending, Nop, ResolSat, Nop, ResClosing, Closein, Broken, Closefail, SendingSat, Start, Unresable, Closefail, Resolving, Nop},
228
229                 /* CONNECTED       */
230                 {Connected, Nop, Sending, Start, SendingSat, Start, Closed, Closeio, Broken, Closeio, Connected, Nop, Disconned, Nop, Connected, Nop},
231
232                 /* DISCONNECTED    */
233                 {Disconned, Nop, Reconning, Connect, ReconSat, Connect, Closed, Closein, Broken, Closein, Connected, Nop, Disconned, Nop, Disconned, Nop},
234
235                 /* RECONNECTING    */
236                 {Reconning, Nop, Reconning, Nop, ReconSat, Nop, ReconClosing, Closein, Broken, Closefail, Sending, Start, Broken, Closefail, Disconned, Nop},
237
238                 /* RECONSATURATED  */
239                 {ReconSat, Nop, Reconning, Nop, ReconSat, Nop, ReconClosing, Closein, Broken, Closefail, SendingSat, Start, Broken, Closefail, Disconned, Nop},
240
241                 /* SENDING         */
242                 {Sending, Nop, Sending, Nop, SendingSat, Nop, Closing, Closein, Disconning, Closeio, Sending, Nop, Reconning, Connect, Connected, Nop},
243
244                 /* SENDINGSATURATED*/
245                 {SendingSat, Nop, Sending, Nop, SendingSat, Nop, Closing, Closein, Disconning, Closeio, SendingSat, Nop, ReconSat, Connect, Connected, Nop},
246
247                 /* RESOLCLOSING    */
248                 {ResClosing, Nop, ResClosing, Nop, ResClosing, Nop, ResClosing, Nop, Broken, Failall, Closing, Start, Unresable, Failall, ResClosing, Nop},
249
250                 /* RECONCLOSING    */
251                 {ReconClosing, Nop, ReconClosing, Nop, ReconClosing, Nop, ReconClosing, Nop, Broken, Failall, Closing, Start, Broken, Failall, ReconClosing, Nop},
252
253                 /* CLOSING         */
254                 {Closing, Nop, Closing, Nop, Closing, Nop, Closing, Nop, Disconning, Closeout, Closing, Nop, ReconClosing, Connect, Closed, Closeout},
255
256                 /* DISCONNECTING   */
257                 {Disconning, Nop, Disconning, Nop, Disconning, Nop, Disconning, Nop, Disconning, Nop, Disconning, Nop, Broken, Failall, Broken, Nop},
258
259                 /* UNRESOLVABLE    */
260                 {Unresable, Nop, Unresable, Nop, Unresable, Nop, Unresable, Nop, Unresable, Nop, Unresable, Closeout, Unresable, Nop, Unresable, Nop},
261
262                 /* CLOSED          */
263                 {Closed, Nop, Closed, Nop, Closed, Nop, Closed, Nop, Closed, Nop, Closed, Closeout, Closed, Nop, Closed, Nop},
264
265                 /* BROKEN          */
266                 {Broken, Nop, Broken, Nop, Broken, Nop, Broken, Nop, Broken, Nop, Broken, Closeout, Broken, Nop, Broken, Nop}
267         };
268
269         static {
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]);
288         }
289     }
290
291     /**
292      * The current state!
293      */
294     private volatile State state = null;
295
296     /**
297      * Constructs a new messenger state machine.
298      * <p/>
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.
302      *
303      * @param connected If <tt>true</tt>, the initial state is {@link Messenger#CONNECTED} otherwise {@link Messenger#UNRESOLVED}.
304      */
305     protected MessengerState(boolean connected) {
306
307         state = connected ? TransitionMap.Connected : TransitionMap.Unresolved;
308     }
309
310     /**
311      * @return The current state.
312      */
313     public int getState() {
314         // getState is always just a peek. It needs no sync.
315         return state.number;
316     }
317
318     /**
319      * Event input.
320      */
321     public void resolveEvent() {
322         Action a = state.acResolve;
323
324         state = state.stResolve;
325         a.doIt(this);
326     }
327
328     /**
329      * Message event
330      */
331     public void msgsEvent() {
332         Action a = state.acMsgs;
333
334         state = state.stMsgs;
335         a.doIt(this);
336     }
337
338     /**
339      * Saturated Event
340      */
341     public void saturatedEvent() {
342         Action a = state.acSaturated;
343
344         state = state.stSaturated;
345         a.doIt(this);
346     }
347
348     /**
349      * Close Event
350      */
351     public void closeEvent() {
352         Action a = state.acClose;
353
354         state = state.stClose;
355         a.doIt(this);
356     }
357
358     /**
359      * Shutdown Event
360      */
361     public void shutdownEvent() {
362         Action a = state.acShutdown;
363
364         state = state.stShutdown;
365         a.doIt(this);
366     }
367
368     /**
369      * Up Event
370      */
371     public void upEvent() {
372         Action a = state.acUp;
373
374         state = state.stUp;
375         a.doIt(this);
376     }
377
378     /**
379      * Down Event
380      */
381     public void downEvent() {
382         Action a = state.acDown;
383
384         state = state.stDown;
385         a.doIt(this);
386     }
387
388     /**
389      * Idle Event
390      */
391     public void idleEvent() {
392         Action a = state.acIdle;
393
394         state = state.stIdle;
395         a.doIt(this);
396     }
397
398     /**
399      * Actions they're always called in sequence by event methods.
400      *
401      * Actions must not call event methods in sequence.
402      **/
403
404     /**
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.
407      */
408     protected abstract void connectAction();
409
410     /**
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.
414      */
415     protected abstract void startAction();
416
417     /**
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.
420      */
421     protected abstract void closeInputAction();
422
423     /**
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.
426      */
427     protected abstract void failAllAction();
428
429     /**
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.
435      * <p/>
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}.
438      * <p/>
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}.
441      */
442     protected abstract void closeOutputAction();
443 }