/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.messaging.util; import java.util.ArrayList; import java.util.List; /** * Provides a generic and loose-coupled framework to execute one primary and multiple fallback * strategies for solving a given task.

* Basically, what would have been a nasty try-catch that's hard to separate and maintain: *


 * try {
 *     // doSomething() that may fail.
 * } catch (Exception ex) {
 *     try {
 *         // fallback1() that may fail.
 *     } catch (Exception ex2) {
 *         try {
 *             // fallback2() that may fail.
 *         } catch (Exception ex3) {
 *             // ...
 *         }
 *     }
 * }
 * 
* Now becomes:
*

 * FallbackStrategies
 *      .startWith(something)
 *      .thenTry(fallback1)
 *      .thenTry(fallback2)
 *      .execute();
 * 
*/ public class FallbackStrategies { public interface Strategy { Output execute(Input params) throws Exception; } private final List> mChainedStrategies; private FallbackStrategies(final Strategy primaryStrategy) { mChainedStrategies = new ArrayList>(); mChainedStrategies.add(primaryStrategy); } public static FallbackStrategies startWith( final Strategy primaryStrategy) { return new FallbackStrategies(primaryStrategy); } public FallbackStrategies thenTry(final Strategy strategy) { Assert.isFalse(mChainedStrategies.isEmpty()); mChainedStrategies.add(strategy); return this; } public Output execute(final Input params) { final int count = mChainedStrategies.size(); for (int i = 0; i < count; i++) { final Strategy strategy = mChainedStrategies.get(i); try { // If succeeds, this will directly return. return strategy.execute(params); } catch (Exception ex) { LogUtil.e(LogUtil.BUGLE_TAG, "Exceptions occured when executing strategy " + strategy + (i < count - 1 ? ", attempting fallback " + mChainedStrategies.get(i + 1) : ", and running out of fallbacks."), ex); // This will fall through and continue with the next strategy (if any). } } // Running out of strategies, return null. // TODO: Should this accept user-defined fallback value other than null? return null; } }