Files
react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/FallbackJSBundleLoader.java
T
Andres SuarezandFacebook Github Bot 3b31e69e28 Tidy up license headers [2/n]
Summary: Changelog: [General] [Fixed] - License header cleanup

Reviewed By: yungsters

Differential Revision: D17952694

fbshipit-source-id: 17c87de7ebb271fa2ac8d00af72a4d1addef8bd0
2019-10-16 10:06:34 -07:00

84 lines
2.5 KiB
Java

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge;
import com.facebook.common.logging.FLog;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Stack;
/**
* FallbackJSBundleLoader
*
* <p>An implementation of {@link JSBundleLoader} that will try to load from multiple sources,
* falling back from one source to the next at load time when an exception is thrown for a
* recoverable error.
*/
public final class FallbackJSBundleLoader extends JSBundleLoader {
/* package */ static final String RECOVERABLE = "facebook::react::Recoverable";
/* package */ static final String TAG = "FallbackJSBundleLoader";
// Loaders to delegate to, with the preferred one at the top.
private Stack<JSBundleLoader> mLoaders;
// Reasons why we fell-back on previous loaders, in order of occurrence.
private final ArrayList<Exception> mRecoveredErrors = new ArrayList<>();
/** @param loaders Loaders for the sources to try, in descending order of preference. */
public FallbackJSBundleLoader(List<JSBundleLoader> loaders) {
mLoaders = new Stack();
ListIterator<JSBundleLoader> it = loaders.listIterator(loaders.size());
while (it.hasPrevious()) {
mLoaders.push(it.previous());
}
}
/**
* This loader delegates to (and so behaves like) the currently preferred loader. If that loader
* fails in a recoverable way and we fall back from it, it is replaced by the next most preferred
* loader.
*/
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
while (true) {
try {
return getDelegateLoader().loadScript(delegate);
} catch (Exception e) {
if (e.getMessage() == null || !e.getMessage().startsWith(RECOVERABLE)) {
throw e;
}
mLoaders.pop();
mRecoveredErrors.add(e);
FLog.wtf(TAG, "Falling back from recoverable error", e);
}
}
}
private JSBundleLoader getDelegateLoader() {
if (!mLoaders.empty()) {
return mLoaders.peek();
}
RuntimeException fallbackException = new RuntimeException("No fallback options available");
// Invariant: tail.getCause() == null
Throwable tail = fallbackException;
for (Exception e : mRecoveredErrors) {
tail.initCause(e);
while (tail.getCause() != null) {
tail = tail.getCause();
}
}
throw fallbackException;
}
}