private List<VFileEvent> getEvents(String msg, @Nullable Runnable action) {
    LOG.debug("** waiting for " + msg);
    myAccept = true;

    if (action != null) {
      action.run();
    }

    int timeout = myTimeout;
    try {
      synchronized (myWaiter) {
        //noinspection WaitNotInLoop
        myWaiter.wait(timeout);
      }
    } catch (InterruptedException e) {
      LOG.warn(e);
    }

    LOG.debug("** waited for " + timeout);
    myFileSystem.refresh(false);

    ArrayList<VFileEvent> result;
    synchronized (myEvents) {
      result = new ArrayList<VFileEvent>(myEvents);
      myEvents.clear();
    }
    LOG.debug("** events: " + result.size());
    return result;
  }
 final void runChange(Runnable change) {
   final boolean b = setChanging(true);
   try {
     change.run();
   } finally {
     setChanging(b);
   }
 }
  public DomManagerImpl(
      Project project,
      SemService semService,
      ConverterManager converterManager,
      DomApplicationComponent appComponent) {
    myProject = project;
    mySemService = semService;
    myConverterManager = converterManager;
    myApplicationComponent = appComponent;

    final PomModel pomModel = PomManager.getModel(project);
    pomModel.addModelListener(
        new PomModelListener() {
          public void modelChanged(PomModelEvent event) {
            if (myChanging) return;

            final XmlChangeSet changeSet =
                (XmlChangeSet) event.getChangeSet(pomModel.getModelAspect(XmlAspect.class));
            if (changeSet != null) {
              for (XmlFile file : changeSet.getChangedFiles()) {
                DomFileElementImpl<DomElement> element = getCachedFileElement(file);
                if (element != null) {
                  fireEvent(new DomEvent(element, false));
                }
              }
            }
          }

          public boolean isAspectChangeInteresting(PomModelAspect aspect) {
            return aspect instanceof XmlAspect;
          }
        },
        project);

    Runnable setupVfsListeners =
        new Runnable() {
          public void run() {
            final VirtualFileAdapter listener =
                new VirtualFileAdapter() {
                  private final List<DomEvent> myDeletionEvents = new SmartList<DomEvent>();

                  public void contentsChanged(VirtualFileEvent event) {
                    if (event.isFromSave()) return;

                    processVfsChange(event.getFile());
                  }

                  public void fileCreated(VirtualFileEvent event) {
                    processVfsChange(event.getFile());
                  }

                  public void beforeFileDeletion(final VirtualFileEvent event) {
                    if (!myProject.isDisposed()) {
                      beforeFileDeletion(event.getFile());
                    }
                  }

                  private void beforeFileDeletion(final VirtualFile file) {
                    if (file.isDirectory() && file instanceof NewVirtualFile) {
                      for (final VirtualFile child : ((NewVirtualFile) file).getCachedChildren()) {
                        beforeFileDeletion(child);
                      }
                      return;
                    }

                    if (file.isValid() && StdFileTypes.XML.equals(file.getFileType())) {
                      final PsiFile psiFile = getCachedPsiFile(file);
                      if (psiFile instanceof XmlFile) {
                        Collections.addAll(
                            myDeletionEvents, recomputeFileElement((XmlFile) psiFile));
                      }
                    }
                  }

                  public void fileDeleted(VirtualFileEvent event) {
                    if (!myDeletionEvents.isEmpty()) {
                      if (!myProject.isDisposed()) {
                        for (DomEvent domEvent : myDeletionEvents) {
                          fireEvent(domEvent);
                        }
                      }
                      myDeletionEvents.clear();
                    }
                  }

                  public void propertyChanged(VirtualFilePropertyEvent event) {
                    final VirtualFile file = event.getFile();
                    if (!file.isDirectory()
                        && VirtualFile.PROP_NAME.equals(event.getPropertyName())) {
                      processVfsChange(file);
                    }
                  }
                };
            VirtualFileManager.getInstance().addVirtualFileListener(listener, myProject);
          }
        };

    StartupManager startupManager = StartupManager.getInstance(project);
    if (!((StartupManagerEx) startupManager).startupActivityPassed()) {
      startupManager.registerStartupActivity(setupVfsListeners);
    } else {
      setupVfsListeners.run();
    }
  }