// Copyright 2004-present Facebook. All Rights Reserved.
package com.facebook.react;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.BaseJavaModule;
import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.OnBatchCompleteListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMarker;
import com.facebook.react.bridge.ReactMarkerConstants;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.cxxbridge.ModuleHolder;
import com.facebook.react.cxxbridge.NativeModuleRegistry;
import com.facebook.react.module.model.ReactModuleInfo;
/**
* Helper class to build NativeModuleRegistry.
*/
public class NativeModuleRegistryBuilder {
private final ReactApplicationContext mReactApplicationContext;
private final boolean mLazyNativeModulesEnabled;
private final Map<Class<? extends NativeModule>, ModuleHolder> mModules = new HashMap<>();
private final Map<String, Class<? extends NativeModule>> namesToType = new HashMap<>();
public NativeModuleRegistryBuilder(
ReactApplicationContext reactApplicationContext,
boolean lazyNativeModulesEnabled) {
mReactApplicationContext = reactApplicationContext;
mLazyNativeModulesEnabled = lazyNativeModulesEnabled;
}
public void processPackage(ReactPackage reactPackage) {
if (mLazyNativeModulesEnabled) {
if (!(reactPackage instanceof LazyReactPackage)) {
throw new IllegalStateException("Lazy native modules requires all ReactPackage to " +
"inherit from LazyReactPackage");
}
LazyReactPackage lazyReactPackage = (LazyReactPackage) reactPackage;
List<ModuleSpec> moduleSpecs = lazyReactPackage.getNativeModules(mReactApplicationContext);
Map<Class, ReactModuleInfo> reactModuleInfoMap = lazyReactPackage.getReactModuleInfoProvider()
.getReactModuleInfos();
for (ModuleSpec moduleSpec : moduleSpecs) {
Class<? extends NativeModule> type = moduleSpec.getType();
ReactModuleInfo reactModuleInfo = reactModuleInfoMap.get(type);
ModuleHolder moduleHolder;
if (reactModuleInfo == null) {
if (BaseJavaModule.class.isAssignableFrom(type)) {
throw new IllegalStateException("Native Java module " + type.getSimpleName() +
" should be annotated with @ReactModule and added to a @ReactModuleList.");
}
ReactMarker.logMarker(
ReactMarkerConstants.CREATE_MODULE_START,
moduleSpec.getType().getSimpleName());
NativeModule module = moduleSpec.getProvider().get();
ReactMarker.logMarker(ReactMarkerConstants.CREATE_MODULE_END);
moduleHolder = new ModuleHolder(module);
} else {
moduleHolder = new ModuleHolder(
reactModuleInfo.name(),
reactModuleInfo.canOverrideExistingModule(),
reactModuleInfo.supportsWebWorkers(),
reactModuleInfo.needsEagerInit(),
moduleSpec.getProvider());
}
String name = moduleHolder.getName();
if (namesToType.containsKey(name)) {
Class<? extends NativeModule> existingNativeModule = namesToType.get(name);
if (!moduleHolder.getCanOverrideExistingModule()) {
throw new IllegalStateException("Native module " + type.getSimpleName() +
" tried to override " + existingNativeModule.getSimpleName() + " for module name " +
name + ". If this was your intention, set canOverrideExistingModule=true");
}
mModules.remove(existingNativeModule);
}
namesToType.put(name, type);
mModules.put(type, moduleHolder);
}
} else {
FLog.d(
ReactConstants.TAG,
reactPackage.getClass().getSimpleName() +
" is not a LazyReactPackage, falling back to old version.");
for (NativeModule nativeModule : reactPackage.createNativeModules(mReactApplicationContext)) {
addNativeModule(nativeModule);
}
}
}
public void addNativeModule(NativeModule nativeModule) {
String name = nativeModule.getName();
Class<? extends NativeModule> type = nativeModule.getClass();
if (namesToType.containsKey(name)) {
Class<? extends NativeModule> existingModule = namesToType.get(name);
if (!nativeModule.canOverrideExistingModule()) {
throw new IllegalStateException("Native module " + type.getSimpleName() +
" tried to override " + existingModule.getSimpleName() + " for module name " +
name + ". If this was your intention, set canOverrideExistingModule=true");
}
mModules.remove(existingModule);
}
namesToType.put(name, type);
ModuleHolder moduleHolder = new ModuleHolder(nativeModule);
mModules.put(type, moduleHolder);
}
public NativeModuleRegistry build() {
ArrayList<ModuleHolder> batchCompleteListenerModules = new ArrayList<>();
for (Map.Entry<Class<? extends NativeModule>, ModuleHolder> entry : mModules.entrySet()) {
if (OnBatchCompleteListener.class.isAssignableFrom(entry.getKey())) {
batchCompleteListenerModules.add(entry.getValue());
}
}
return new NativeModuleRegistry(mModules, batchCompleteListenerModules);
}
}