docs: protected boolean installIntoWebContainer(WAB wab) {
          Bundle bundle = wab.getBundle();
          String contextRoot = wab.getContextRoot();
          //hold a lock to prevent deactivation of 'this' component while work is in progress
          deactivationLock.readLock().lock();
          try {
              if (this.deactivated.get() == true) {
                  //we seem to be attempting to deploy a WAB concurrently with the de-activation of
                  // this WAB installer from another thread
                  if (tc.isDebugEnabled()) {
                      Tr.debug(tc, "installIntoWebContainer(WAB) entered by thread after component deactivation",
                               wab);
                  }
                  return false;
              }
              ModuleHandler webModuleHandler = webModuleHandlerSRRef.getService();
              if (webModuleHandler != null) {
                  // Do a quick test to make sure we're not shutting down, bomb out if we are
                  if (FrameworkState.isStopping()) {
                      return false;
                  }
  
                  // Get the wiring for the bundle
                  BundleWiring wiring = bundle.adapt(BundleWiring.class);
                  if (wiring == null) {
                      postFailureEvent(wab, "wab.install.fail.wiring", bundle, contextRoot);
                      Tr.error(tc, "wab.install.fail.wiring", bundle, contextRoot);
                      return false;
                  }
  
                  Container wabContainer = getContainerForBundle(wab, bundle, contextRoot);
  
                  Entry manifestEntry = wabContainer.getEntry("/META-INF/MANIFEST.MF");
                  if (manifestEntry != null) {
                      NonPersistentCache cache = manifestEntry.adapt(NonPersistentCache.class);
                      cache.addToCache(Dictionary.class, bundle.getHeaders(""));
                  }
  
                  // Get the classloader for the bundle
                  ClassLoader loader = wiring.getClassLoader();
  
                  // create a classes info that reflects the bundle wiring so that we can
                  // put that into the overlay cache to supersede the JEE classes info
                  WebModuleClassesInfo classesInfo = getClassesInfo(wab, wabContainer, bundle, contextRoot, wiring);
                  // classesInfo is known to be non-null - getClassesInfo always constructs a new one
                  NonPersistentCache npc = wabContainer.adapt(NonPersistentCache.class);
                  npc.addToCache(WebModuleClassesInfo.class, classesInfo);
  
                  // Use the name of the bundle as its module path within the EBA.
                  final String modPath = bundle.getSymbolicName();
  
                  if (!contextRoot.startsWith("/")) {
                      contextRoot = "/" + contextRoot;
                  }
  
                  // Now find the parent application, WABs are always grouped together according to their owning EBA
                  EbaProvider ebaProviderService = ebaProviderTracker.getService();
                  ExtendedApplicationInfo appInfo = null;
                  //an EBA provider is only available if EBAs are available, system WABs do without this grouping
                  if (ebaProviderService != null) {
                      appInfo = (ExtendedApplicationInfo) ebaProviderService.getApplicationInfo(bundle);
                  }
  
                  if (appInfo == null) {
                      //Standalone WAB
                      //need to create an app info for it
                      String moduleURI = ModuleInfoUtils.getModuleURIFromLocation(modPath);
                      String moduleName = ModuleInfoUtils.getModuleName(wabContainer.adapt(WebApp.class), moduleURI);
                      appInfo = applicationInfoFactorySRRef.getService().createApplicationInfo(modPath,
                                                                                               moduleName,
                                                                                               wabContainer,
                                                                                               null,
                                                                                               null);
                      wab.setCreatedApplicationInfo();
                  }
                  wab.setApplicationInfo(appInfo);
  
                  WABGroup wabGroup;
                  // Using old fashion locks here. Can revisit when we can use Java 8.
                  boolean groupsLocked = true;
                  wabGroupsLock.lock();
                  try {
                      wabGroup = wabGroups.get(appInfo.getName());
                      if (wabGroup == null) {
                          wabGroup = new WABGroup(new WABDeployedAppInfo(deployedAppServicesSRRef.getService(), appInfo));
                          wabGroups.put(appInfo.getName(), wabGroup);
                      }
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          //Note: this trace string is checked in FAT tests
                          Tr.debug(tc, "installIntoWebContainer wabGroups.putIfAbsent(" + appInfo.getName() + " , " + wabGroup + ") ==> " + wabGroup);
                      }
  
                      //We need to make sure that the initial addWebContainerApplication calls
                      //have completed before we try to add any new modules to the application.
                      synchronized (wabGroup) {
                          WABDeployedAppInfo deployedApp = (WABDeployedAppInfo) wabGroup.getDeployedAppInfo();
  
                          //add the WAB to the WAB group (we add standalone WABs to a group, but they'll only ever have one WAB in the group)
                          wabGroup.addWab(wab, this);
                          groupsLocked = false;
                          wabGroupsLock.unlock();
  
                          ModuleContainerInfo mci = deployedApp.createModuleContainerInfo(webModuleHandler, contextRoot, wabContainer, modPath, loader);
                          wab.setModuleContainerInfo(mci);
                          if (wab.getCreatedApplicationInfo()) {
                              if (!deployedApp.installApp(wab)) {
                                  postFailureEvent(wab, "wab.install.fail", bundle, contextRoot);
                                  Tr.error(tc, "wab.install.fail", bundle, contextRoot);
                                  return false;
                              }
                          } else {
                              if (!deployedApp.installModule(wab)) {
                                  postFailureEvent(wab, "wab.install.fail", bundle, contextRoot);
                                  Tr.error(tc, "wab.install.fail", bundle, contextRoot);
                                  return false;
                              }
                          }
  
                          //register the WAB bundle with a key that can be looked up elsewhere
                          //based on the J2EEName form
                          Dictionary<String, Object> bRegProps = new Hashtable<String, Object>(1);
                          bRegProps.put("web.module.key", appInfo.getName() + "#" + deployedApp.getModuleName(mci));
                          bRegProps.put("installed.wab.contextRoot", contextRoot);
                          bRegProps.put("installed.wab.container", wabContainer);
                          ServiceRegistration<Bundle> reg = ctx.registerService(Bundle.class, bundle, bRegProps);
                          wab.setRegistration(reg);
                      }
                  } finally {
                      if (groupsLocked) {
                          wabGroupsLock.unlock();
                      }
                  }
              } else {
                  postFailureEvent(wab, "wab.install.fail.container", bundle, contextRoot);
                  Tr.error(tc, "wab.install.fail.container", bundle, contextRoot);
                  return false;
              }
          } catch (Throwable e) {
              postEvent(wab.createFailedEvent(e));
              // we won't be able to install the WAB. Issue error message.
              Tr.error(tc, "wab.install.fail", bundle, contextRoot);
              return false;
          } finally {
              deactivationLock.readLock().unlock();
          }
          return true;
      }