1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.net.utils;
18 
19 /**
20  * SimpleStateMachine provides a minimal, synchronous state machine framework.
21  *
22  * <p>This state machine is of limited functionality, but sufficient for implementation of simple
23  * protocols. Due to the limited functionality, it is also easy to read and maintain.
24  *
25  * SimpleStateMachine defaults to the null state. Implementers should immediately transition
26  * to their default state when instantiated.
27  *
28  * @param <T> The input message type.
29  * @param <R> The result type. For SimpleStateMachines without a return value, use {@link
30  *     java.lang.Void}
31  */
32 public abstract class SimpleStateMachine<T, R> {
33     protected final SimpleState mNullState =
34             new SimpleState() {
35                 public R process(T msg) {
36                     throw new IllegalStateException("Process called on null state");
37                 }
38             };
39 
40     protected SimpleState mState = mNullState;
41 
42     // Non-static to allow for compiler verification of T, R from SimpleStateMachine
43     protected abstract class SimpleState {
process(T msg)44         public abstract R process(T msg);
45     }
46 
47     /**
48      * Processes the given message based on the current {@link SimpleState}
49      *
50      * @param msg The message to be processed by the current state
51      * @return The result of the processing by the current state
52      */
process(T msg)53     public R process(T msg) {
54         return mState.process(msg);
55     }
56 
57     /**
58      * Transitions to a new state
59      *
60      * @param newState The {@link SimpleState} that the {@link SimpleStateMachine} should
61      *     transition to
62      * @throws IllegalArgumentException if newState is null
63      */
transitionTo(SimpleState newState)64     protected void transitionTo(SimpleState newState) {
65         if (newState == null) {
66             throw new IllegalArgumentException("SimpleState value must be non-null.");
67         }
68 
69         mState = newState;
70     }
71 
72     /**
73      * Transitions to a new state, and lets the new state process the given message
74      *
75      * @param newState The {@link SimpleState} that the {@link SimpleStateMachine} should transition
76      *     to. This state will immediately be requested to process the given message.
77      * @param msg The message that should be processed by the new state
78      * @return The result of the processing by the new state
79      * @throws IllegalArgumentException if newState is null
80      */
transitionAndProcess(SimpleState newState, T msg)81     protected R transitionAndProcess(SimpleState newState, T msg) {
82         transitionTo(newState);
83         return mState.process(msg);
84     }
85 }
86