public static void addLibrary(
     Module module, String libName, String libDir, String[] classRoots, String[] sourceRoots) {
   String proto =
       (classRoots.length > 0 ? classRoots[0] : sourceRoots[0]).endsWith(".jar!/")
           ? JarFileSystem.PROTOCOL
           : LocalFileSystem.PROTOCOL;
   String parentUrl = VirtualFileManager.constructUrl(proto, libDir);
   List<String> classesUrls = new ArrayList<>();
   List<String> sourceUrls = new ArrayList<>();
   for (String classRoot : classRoots) {
     classesUrls.add(parentUrl + classRoot);
   }
   for (String sourceRoot : sourceRoots) {
     sourceUrls.add(parentUrl + sourceRoot);
   }
   ModuleRootModificationUtil.addModuleLibrary(module, libName, classesUrls, sourceUrls);
 }
 @Override
 public void addProjectManagerListener(
     @NotNull Project project, @NotNull ProjectManagerListener listener) {
   List<ProjectManagerListener> listeners = project.getUserData(LISTENERS_IN_PROJECT_KEY);
   if (listeners == null) {
     listeners =
         ((UserDataHolderEx) project)
             .putUserDataIfAbsent(
                 LISTENERS_IN_PROJECT_KEY,
                 ContainerUtil.<ProjectManagerListener>createLockFreeCopyOnWriteList());
   }
   listeners.add(listener);
 }
 public static void addLibrary(
     Module module, ModifiableRootModel model, String libName, String libPath, String... jarArr) {
   List<VirtualFile> classesRoots = new ArrayList<>();
   for (String jar : jarArr) {
     if (!libPath.endsWith("/") && !jar.startsWith("/")) {
       jar = "/" + jar;
     }
     String path = libPath + jar;
     VirtualFile root;
     if (path.endsWith(".jar")) {
       root = JarFileSystem.getInstance().refreshAndFindFileByPath(path + "!/");
     } else {
       root = LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
     }
     assert root != null : "Library root folder not found: " + path + "!/";
     classesRoots.add(root);
   }
   addProjectLibrary(module, model, libName, classesRoots, Collections.emptyList());
 }
  private void askToReloadProjectIfConfigFilesChangedExternally() {
    LOG.debug("[RELOAD] myReloadBlockCount = " + myReloadBlockCount.get());
    if (myReloadBlockCount.get() == 0) {
      Set<Project> projects;

      synchronized (myChangedProjectFiles) {
        if (myChangedProjectFiles.isEmpty()) return;
        projects = new HashSet<Project>(myChangedProjectFiles.keySet());
      }

      List<Project> projectsToReload = new ArrayList<Project>();

      for (Project project : projects) {
        if (shouldReloadProject(project)) {
          projectsToReload.add(project);
        }
      }

      for (final Project projectToReload : projectsToReload) {
        reloadProjectImpl(projectToReload, false);
      }
    }
  }
  @Override
  public boolean openProject(final Project project) {
    if (isLight(project)) {
      throw new AssertionError("must not open light project");
    }
    final Application application = ApplicationManager.getApplication();

    if (!application.isUnitTestMode() && !((ProjectEx) project).getStateStore().checkVersion()) {
      return false;
    }

    synchronized (myOpenProjects) {
      if (myOpenProjects.contains(project)) {
        return false;
      }
      myOpenProjects.add(project);
      cacheOpenProjects();
    }
    fireProjectOpened(project);

    final StartupManagerImpl startupManager =
        (StartupManagerImpl) StartupManager.getInstance(project);
    waitForFileWatcher(project);
    boolean ok =
        myProgressManager.runProcessWithProgressSynchronously(
            new Runnable() {
              @Override
              public void run() {
                startupManager.runStartupActivities();

                // dumb mode should start before post-startup activities
                // only when startCacheUpdate is called from UI thread, we can guarantee that
                // when the method returns, the application has entered dumb mode
                UIUtil.invokeAndWaitIfNeeded(
                    new Runnable() {
                      @Override
                      public void run() {
                        startupManager.startCacheUpdate();
                      }
                    });

                startupManager.runPostStartupActivitiesFromExtensions();

                UIUtil.invokeLaterIfNeeded(
                    new Runnable() {
                      @Override
                      public void run() {
                        startupManager.runPostStartupActivities();
                      }
                    });
              }
            },
            ProjectBundle.message("project.load.progress"),
            true,
            project);

    if (!ok) {
      closeProject(project, false, false, true);
      notifyProjectOpenFailed();
      return false;
    }

    if (!application.isHeadlessEnvironment() && !application.isUnitTestMode()) {
      // should be invoked last
      startupManager.runWhenProjectIsInitialized(
          new Runnable() {
            @Override
            public void run() {
              final TrackingPathMacroSubstitutor macroSubstitutor =
                  ((ProjectEx) project)
                      .getStateStore()
                      .getStateStorageManager()
                      .getMacroSubstitutor();
              if (macroSubstitutor != null) {
                StorageUtil.notifyUnknownMacros(macroSubstitutor, project, null);
              }
            }
          });
    }

    return true;
  }
 @Override
 public void addProjectManagerListener(@NotNull ProjectManagerListener listener) {
   myListeners.add(listener);
 }