private boolean tryToReloadApplication() {
    try {
      final Application app = ApplicationManager.getApplication();

      if (app.isDisposed()) return false;
      final HashSet<Pair<VirtualFile, StateStorage>> causes =
          new HashSet<Pair<VirtualFile, StateStorage>>(myChangedApplicationFiles);
      if (causes.isEmpty()) return true;

      final boolean[] reloadOk = {false};
      final LinkedHashSet<String> components = new LinkedHashSet<String>();

      ApplicationManager.getApplication()
          .runWriteAction(
              new Runnable() {
                @Override
                public void run() {
                  try {
                    reloadOk[0] =
                        ((ApplicationImpl) app).getStateStore().reload(causes, components);
                  } catch (StateStorageException e) {
                    Messages.showWarningDialog(
                        ProjectBundle.message("project.reload.failed", e.getMessage()),
                        ProjectBundle.message("project.reload.failed.title"));
                  } catch (IOException e) {
                    Messages.showWarningDialog(
                        ProjectBundle.message("project.reload.failed", e.getMessage()),
                        ProjectBundle.message("project.reload.failed.title"));
                  }
                }
              });

      if (!reloadOk[0] && !components.isEmpty()) {
        String message = "Application components were changed externally and cannot be reloaded:\n";
        for (String component : components) {
          message += component + "\n";
        }

        final boolean canRestart = ApplicationManager.getApplication().isRestartCapable();
        message += "Would you like to " + (canRestart ? "restart " : "shutdown ");
        message += ApplicationNamesInfo.getInstance().getProductName() + "?";

        if (Messages.showYesNoDialog(
                message, "Application Configuration Reload", Messages.getQuestionIcon())
            == Messages.YES) {
          for (Pair<VirtualFile, StateStorage> cause : causes) {
            StateStorage stateStorage = cause.getSecond();
            if (stateStorage instanceof XmlElementStorage) {
              ((XmlElementStorage) stateStorage).disableSaving();
            }
          }
          ApplicationManagerEx.getApplicationEx().restart(true);
        }
      }

      return reloadOk[0];
    } finally {
      myChangedApplicationFiles.clear();
    }
  }
  private void initProject(@NotNull ProjectImpl project, @Nullable ProjectImpl template)
      throws IOException {
    final ProgressIndicator indicator = myProgressManager.getProgressIndicator();
    if (indicator != null && !project.isDefault()) {
      indicator.setText(ProjectBundle.message("loading.components.for", project.getName()));
      indicator.setIndeterminate(true);
    }

    ApplicationManager.getApplication()
        .getMessageBus()
        .syncPublisher(ProjectLifecycleListener.TOPIC)
        .beforeProjectLoaded(project);

    try {
      if (template != null) {
        project.getStateStore().loadProjectFromTemplate(template);
      } else {
        project.getStateStore().load();
      }
      project.loadProjectComponents();
      project.init();
    } catch (IOException e) {
      scheduleDispose(project);
      throw e;
    } catch (ProcessCanceledException e) {
      scheduleDispose(project);
      throw e;
    }
  }
  private void scheduleReloadApplicationAndProject() {
    // todo: commented due to "IDEA-61938 Libraries configuration is kept if switching branches"
    // because of save which may happen _before_ project reload ;(

    // ApplicationManager.getApplication().invokeLater(new Runnable() {
    //  public void run() {
    // IdeEventQueue.getInstance().addIdleListener(new Runnable() {
    //  @Override
    //  public void run() {
    //    IdeEventQueue.getInstance().removeIdleListener(this);
    ApplicationManager.getApplication()
        .invokeLater(
            new Runnable() {
              @Override
              public void run() {
                if (!tryToReloadApplication()) return;
                askToReloadProjectIfConfigFilesChangedExternally();
              }
            },
            ModalityState.NON_MODAL);
    // }
    // }, 2000);
    // }
    // }, ModalityState.NON_MODAL);
  }
 @Override
 @NotNull
 public Project[] getOpenProjects() {
   synchronized (myOpenProjects) {
     if (myOpenProjectsArrayCache.length != myOpenProjects.size()) {
       LOG.error(
           "Open projects: "
               + myOpenProjects
               + "; cache: "
               + Arrays.asList(myOpenProjectsArrayCache));
     }
     if (myOpenProjectsArrayCache.length > 0
         && myOpenProjectsArrayCache[0] != myOpenProjects.get(0)) {
       LOG.error(
           "Open projects cache corrupted. Open projects: "
               + myOpenProjects
               + "; cache: "
               + Arrays.asList(myOpenProjectsArrayCache));
     }
     if (ApplicationManager.getApplication().isUnitTestMode()) {
       Project[] testProjects = myTestProjects.toArray(new Project[myTestProjects.size()]);
       for (Project testProject : testProjects) {
         assert !testProject.isDisposed() : testProject;
       }
       return ArrayUtil.mergeArrays(myOpenProjectsArrayCache, testProjects);
     }
     return myOpenProjectsArrayCache;
   }
 }
 private static void notifyProjectOpenFailed() {
   ApplicationManager.getApplication()
       .getMessageBus()
       .syncPublisher(AppLifecycleListener.TOPIC)
       .projectOpenFailed();
   WelcomeFrame.showIfNoProjectOpened();
 }
 @Override
 public boolean isProjectOpened(Project project) {
   synchronized (myOpenProjects) {
     return ApplicationManager.getApplication().isUnitTestMode()
             && myTestProjects.contains(project)
         || myOpenProjects.contains(project);
   }
 }
 @Override
 public void openTestProject(@NotNull final Project project) {
   synchronized (myOpenProjects) {
     assert ApplicationManager.getApplication().isUnitTestMode();
     assert !project.isDisposed() : "Must not open already disposed project";
     myTestProjects.add(project);
   }
 }
 @Override
 public Collection<Project> closeTestProject(@NotNull Project project) {
   synchronized (myOpenProjects) {
     assert ApplicationManager.getApplication().isUnitTestMode();
     myTestProjects.remove(project);
     return myTestProjects;
   }
 }
 public static void addExcludedRoot(Module module, VirtualFile dir) {
   ModuleRootModificationUtil.updateModel(
       module,
       model ->
           ApplicationManager.getApplication()
               .runReadAction(
                   () -> {
                     findContentEntryWithAssertion(model, dir).addExcludeFolder(dir);
                   }));
 }
  @Override
  public void disposeComponent() {
    ApplicationManager.getApplication().assertWriteAccessAllowed();
    Disposer.dispose(myChangedFilesAlarm);
    if (myDefaultProject != null) {
      Disposer.dispose(myDefaultProject);

      myDefaultProject = null;
      myDefaultProjectWasDisposed = true;
    }
  }
  @Override
  @Nullable
  public Project newProject(
      final String projectName,
      @NotNull String filePath,
      boolean useDefaultProjectSettings,
      boolean isDummy) {
    filePath = toCanonicalName(filePath);

    //noinspection ConstantConditions
    if (LOG_PROJECT_LEAKAGE_IN_TESTS && ApplicationManager.getApplication().isUnitTestMode()) {
      for (int i = 0; i < 42; i++) {
        if (myProjects.size() < MAX_LEAKY_PROJECTS) break;
        System.gc();
        TimeoutUtil.sleep(100);
        System.gc();
      }

      if (myProjects.size() >= MAX_LEAKY_PROJECTS) {
        List<Project> copy = new ArrayList<Project>(myProjects.keySet());
        myProjects.clear();
        throw new TooManyProjectLeakedException(copy);
      }
    }

    ProjectImpl project =
        createProject(
            projectName, filePath, false, ApplicationManager.getApplication().isUnitTestMode());
    try {
      initProject(project, useDefaultProjectSettings ? (ProjectImpl) getDefaultProject() : null);
      if (LOG_PROJECT_LEAKAGE_IN_TESTS) {
        myProjects.put(project, null);
      }
      return project;
    } catch (final Exception e) {
      LOG.info(e);
      Messages.showErrorDialog(message(e), ProjectBundle.message("project.load.default.error"));
    }
    return null;
  }
  public void reloadProjectImpl(@NotNull final Project p, final boolean clearCopyToRestore) {
    if (clearCopyToRestore) {
      mySavedCopies.clear();
      mySavedTimestamps.clear();
    }

    final Project[] project = {p};

    ProjectReloadState.getInstance(project[0]).onBeforeAutomaticProjectReload();
    final Application application = ApplicationManager.getApplication();

    application.invokeLater(
        new Runnable() {
          @Override
          public void run() {
            LOG.debug("Reloading project.");
            ProjectImpl projectImpl = (ProjectImpl) project[0];
            if (projectImpl.isDisposed()) return;
            IProjectStore projectStore = projectImpl.getStateStore();
            final String location = projectImpl.getPresentableUrl();

            final List<IFile> original;
            try {
              final IComponentStore.SaveSession saveSession = projectStore.startSave();
              original = saveSession.getAllStorageFiles(true);
              saveSession.finishSave();
            } catch (IOException e) {
              LOG.error(e);
              return;
            }

            if (project[0].isDisposed() || ProjectUtil.closeAndDispose(project[0])) {
              application.runWriteAction(
                  new Runnable() {
                    @Override
                    public void run() {
                      for (final IFile originalFile : original) {
                        restoreCopy(
                            LocalFileSystem.getInstance().refreshAndFindFileByIoFile(originalFile));
                      }
                    }
                  });

              project[0] = null; // Let it go.

              ProjectUtil.openProject(location, null, true);
            }
          }
        },
        ModalityState.NON_MODAL);
  }
  public boolean closeProject(
      @NotNull final Project project,
      final boolean save,
      final boolean dispose,
      boolean checkCanClose) {
    if (isLight(project)) {
      throw new AssertionError("must not close light project");
    }
    if (!isProjectOpened(project)) return true;
    if (checkCanClose && !canClose(project)) return false;
    final ShutDownTracker shutDownTracker = ShutDownTracker.getInstance();
    shutDownTracker.registerStopperThread(Thread.currentThread());
    try {
      if (save) {
        FileDocumentManager.getInstance().saveAllDocuments();
        project.save();
      }

      if (checkCanClose && !ensureCouldCloseIfUnableToSave(project)) {
        return false;
      }

      fireProjectClosing(project); // somebody can start progress here, do not wrap in write action

      ApplicationManager.getApplication()
          .runWriteAction(
              new Runnable() {
                @Override
                public void run() {
                  synchronized (myOpenProjects) {
                    myOpenProjects.remove(project);
                    cacheOpenProjects();
                    myTestProjects.remove(project);
                  }

                  myChangedProjectFiles.remove(project);

                  fireProjectClosed(project);

                  if (dispose) {
                    Disposer.dispose(project);
                  }
                }
              });
    } finally {
      shutDownTracker.unregisterStopperThread(Thread.currentThread());
    }

    return true;
  }
 @Override
 @NotNull
 public synchronized Project getDefaultProject() {
   LOG.assertTrue(!myDefaultProjectWasDisposed, "Default project has been already disposed!");
   if (myDefaultProject == null) {
     try {
       myDefaultProject =
           createProject(null, "", true, ApplicationManager.getApplication().isUnitTestMode());
       initProject(myDefaultProject, null);
       myDefaultProjectRootElement = null;
     } catch (IOException e) {
       LOG.error(e);
     } catch (StateStorageException e) {
       LOG.error(e);
     }
   }
   return myDefaultProject;
 }
  private static void scheduleDispose(final ProjectImpl project) {
    if (project.isDefault()) {
      return;
    }

    ApplicationManager.getApplication()
        .invokeLater(
            new Runnable() {
              @Override
              public void run() {
                ApplicationManager.getApplication()
                    .runWriteAction(
                        new Runnable() {
                          @Override
                          public void run() {
                            if (!project.isDisposed()) {
                              Disposer.dispose(project);
                            }
                          }
                        });
              }
            });
  }
  @Override
  public Project loadAndOpenProject(@NotNull final String filePath) throws IOException {
    final Project project = convertAndLoadProject(filePath);
    if (project == null) {
      WelcomeFrame.showIfNoProjectOpened();
      return null;
    }

    // todo unify this logic with PlatformProjectOpenProcessor
    if (!openProject(project)) {
      WelcomeFrame.showIfNoProjectOpened();
      ApplicationManager.getApplication()
          .runWriteAction(
              new Runnable() {
                @Override
                public void run() {
                  Disposer.dispose(project);
                }
              });
    }

    return project;
  }
  @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;
  }
  /** @noinspection UnusedParameters */
  public ProjectManagerImpl(
      VirtualFileManager virtualFileManager,
      RecentProjectsManagerBase recentProjectsManager,
      ProgressManager progressManager) {
    myProgressManager = progressManager;
    Application app = ApplicationManager.getApplication();
    MessageBus messageBus = app.getMessageBus();
    MessageBusConnection connection = messageBus.connect(app);
    connection.subscribe(
        StateStorage.STORAGE_TOPIC,
        new StateStorage.Listener() {
          @Override
          public void storageFileChanged(
              @NotNull final VirtualFileEvent event, @NotNull final StateStorage storage) {
            VirtualFile file = event.getFile();
            if (!file.isDirectory()
                && !(event.getRequestor() instanceof StateStorage.SaveSession)) {
              saveChangedProjectFile(file, null, storage);
            }
          }
        });
    final ProjectManagerListener busPublisher = messageBus.syncPublisher(TOPIC);

    addProjectManagerListener(
        new ProjectManagerListener() {
          @Override
          public void projectOpened(final Project project) {
            MessageBus messageBus = project.getMessageBus();
            MessageBusConnection connection = messageBus.connect(project);
            connection.subscribe(
                StateStorage.STORAGE_TOPIC,
                new StateStorage.Listener() {
                  @Override
                  public void storageFileChanged(
                      @NotNull final VirtualFileEvent event, @NotNull final StateStorage storage) {
                    VirtualFile file = event.getFile();
                    if (!file.isDirectory()
                        && !(event.getRequestor() instanceof StateStorage.SaveSession)) {
                      saveChangedProjectFile(file, project, storage);
                    }
                  }
                });

            busPublisher.projectOpened(project);
            for (ProjectManagerListener listener : getListeners(project)) {
              listener.projectOpened(project);
            }
          }

          @Override
          public void projectClosed(Project project) {
            busPublisher.projectClosed(project);
            for (ProjectManagerListener listener : getListeners(project)) {
              listener.projectClosed(project);
            }
          }

          @Override
          public boolean canCloseProject(Project project) {
            for (ProjectManagerListener listener : getListeners(project)) {
              if (!listener.canCloseProject(project)) {
                return false;
              }
            }
            return true;
          }

          @Override
          public void projectClosing(Project project) {
            busPublisher.projectClosing(project);
            for (ProjectManagerListener listener : getListeners(project)) {
              listener.projectClosing(project);
            }
          }
        });

    registerExternalProjectFileListener(virtualFileManager);
  }
 public static boolean isLight(@NotNull Project project) {
   return ApplicationManager.getApplication().isUnitTestMode()
       && project.toString().contains("light_temp_");
 }
  private boolean shouldReloadProject(final Project project) {
    if (project.isDisposed()) return false;
    final HashSet<Pair<VirtualFile, StateStorage>> causes =
        new HashSet<Pair<VirtualFile, StateStorage>>();

    synchronized (myChangedProjectFiles) {
      final List<Pair<VirtualFile, StateStorage>> changes = myChangedProjectFiles.remove(project);
      if (changes != null) {
        causes.addAll(changes);
      }

      if (causes.isEmpty()) return false;
    }

    final boolean[] reloadOk = {false};

    ApplicationManager.getApplication()
        .runWriteAction(
            new Runnable() {
              @Override
              public void run() {
                try {
                  LOG.debug("[RELOAD] Reloading project/components...");
                  reloadOk[0] = ((ProjectEx) project).getStateStore().reload(causes);
                } catch (StateStorageException e) {
                  Messages.showWarningDialog(
                      ProjectBundle.message("project.reload.failed", e.getMessage()),
                      ProjectBundle.message("project.reload.failed.title"));
                } catch (IOException e) {
                  Messages.showWarningDialog(
                      ProjectBundle.message("project.reload.failed", e.getMessage()),
                      ProjectBundle.message("project.reload.failed.title"));
                }
              }
            });
    if (reloadOk[0]) return false;

    String message;
    if (causes.size() == 1) {
      message =
          ProjectBundle.message(
              "project.reload.external.change.single",
              causes.iterator().next().first.getPresentableUrl());
    } else {
      StringBuilder filesBuilder = new StringBuilder();
      boolean first = true;
      Set<String> alreadyShown = new HashSet<String>();
      for (Pair<VirtualFile, StateStorage> cause : causes) {
        String url = cause.first.getPresentableUrl();
        if (!alreadyShown.contains(url)) {
          if (alreadyShown.size() > 10) {
            filesBuilder
                .append("\n" + "and ")
                .append(causes.size() - alreadyShown.size())
                .append(" more");
            break;
          }
          if (!first) filesBuilder.append("\n");
          first = false;
          filesBuilder.append(url);
          alreadyShown.add(url);
        }
      }
      message =
          ProjectBundle.message("project.reload.external.change.multiple", filesBuilder.toString());
    }

    return Messages.showTwoStepConfirmationDialog(
            message,
            ProjectBundle.message("project.reload.external.change.title"),
            "Reload project",
            Messages.getQuestionIcon())
        == 0;
  }