1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/fxa/login/FxAccountLoginStateMachine.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,84 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.fxa.login; 1.9 + 1.10 +import java.security.NoSuchAlgorithmException; 1.11 +import java.util.HashSet; 1.12 +import java.util.Set; 1.13 + 1.14 +import org.mozilla.gecko.background.fxa.FxAccountClient; 1.15 +import org.mozilla.gecko.browserid.BrowserIDKeyPair; 1.16 +import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.Transition; 1.17 +import org.mozilla.gecko.fxa.login.State.StateLabel; 1.18 + 1.19 +public class FxAccountLoginStateMachine { 1.20 + public static final String LOG_TAG = FxAccountLoginStateMachine.class.getSimpleName(); 1.21 + 1.22 + public interface LoginStateMachineDelegate { 1.23 + public FxAccountClient getClient(); 1.24 + public long getCertificateDurationInMilliseconds(); 1.25 + public long getAssertionDurationInMilliseconds(); 1.26 + public void handleTransition(Transition transition, State state); 1.27 + public void handleFinal(State state); 1.28 + public BrowserIDKeyPair generateKeyPair() throws NoSuchAlgorithmException; 1.29 + } 1.30 + 1.31 + public static class ExecuteDelegate { 1.32 + protected final LoginStateMachineDelegate delegate; 1.33 + protected final StateLabel desiredStateLabel; 1.34 + // It's as difficult to detect arbitrary cycles as repeated states. 1.35 + protected final Set<StateLabel> stateLabelsSeen = new HashSet<StateLabel>(); 1.36 + 1.37 + protected ExecuteDelegate(StateLabel initialStateLabel, StateLabel desiredStateLabel, LoginStateMachineDelegate delegate) { 1.38 + this.delegate = delegate; 1.39 + this.desiredStateLabel = desiredStateLabel; 1.40 + this.stateLabelsSeen.add(initialStateLabel); 1.41 + } 1.42 + 1.43 + public FxAccountClient getClient() { 1.44 + return delegate.getClient(); 1.45 + } 1.46 + 1.47 + public long getCertificateDurationInMilliseconds() { 1.48 + return delegate.getCertificateDurationInMilliseconds(); 1.49 + } 1.50 + 1.51 + public long getAssertionDurationInMilliseconds() { 1.52 + return delegate.getAssertionDurationInMilliseconds(); 1.53 + } 1.54 + 1.55 + public BrowserIDKeyPair generateKeyPair() throws NoSuchAlgorithmException { 1.56 + return delegate.generateKeyPair(); 1.57 + } 1.58 + 1.59 + public void handleTransition(Transition transition, State state) { 1.60 + // Always trigger the transition callback. 1.61 + delegate.handleTransition(transition, state); 1.62 + 1.63 + // Possibly trigger the final callback. We trigger if we're at our desired 1.64 + // state, or if we've seen this state before. 1.65 + StateLabel stateLabel = state.getStateLabel(); 1.66 + if (stateLabel == desiredStateLabel || stateLabelsSeen.contains(stateLabel)) { 1.67 + delegate.handleFinal(state); 1.68 + return; 1.69 + } 1.70 + 1.71 + // If this wasn't the last state, leave a bread crumb and move on to the 1.72 + // next state. 1.73 + stateLabelsSeen.add(stateLabel); 1.74 + state.execute(this); 1.75 + } 1.76 + } 1.77 + 1.78 + public void advance(State initialState, final StateLabel desiredStateLabel, final LoginStateMachineDelegate delegate) { 1.79 + if (initialState.getStateLabel() == desiredStateLabel) { 1.80 + // We're already where we want to be! 1.81 + delegate.handleFinal(initialState); 1.82 + return; 1.83 + } 1.84 + ExecuteDelegate executeDelegate = new ExecuteDelegate(initialState.getStateLabel(), desiredStateLabel, delegate); 1.85 + initialState.execute(executeDelegate); 1.86 + } 1.87 +}