private void annotateExternally(
      @NotNull final VirtualFile root,
      @NotNull final PsiModifierListOwner listOwner,
      @NotNull final Project project,
      @NotNull final String packageName,
      @NotNull final String annotationFQName,
      @NotNull final PsiFile fromFile,
      @Nullable final PsiNameValuePair[] value) {
    List<XmlFile> xmlFiles = findExternalAnnotationsXmlFiles(listOwner);

    final XmlFile existingXml = findXmlFileInRoot(xmlFiles, root);
    if (existingXml != null && !CodeInsightUtilBase.preparePsiElementForWrite(existingXml)) {
      notifyAfterAnnotationChanging(listOwner, annotationFQName, false);
      return;
    }

    final List<PsiFile> annotationFiles =
        xmlFiles == null ? new ArrayList<PsiFile>() : new ArrayList<PsiFile>(xmlFiles);

    new WriteCommandAction(project) {
      @Override
      protected void run(final Result result) throws Throwable {
        if (existingXml != null) {
          annotateExternally(listOwner, annotationFQName, existingXml, fromFile, value);
        } else {
          XmlFile newXml = createAnnotationsXml(root, packageName);
          if (newXml == null) {
            notifyAfterAnnotationChanging(listOwner, annotationFQName, false);
          } else {
            annotationFiles.add(newXml);
            myExternalAnnotations.put(getFQN(packageName, fromFile), annotationFiles);
            annotateExternally(listOwner, annotationFQName, newXml, fromFile, value);
          }
        }

        UndoManager.getInstance(project)
            .undoableActionPerformed(
                new BasicUndoableAction() {
                  @Override
                  public void undo() {
                    dropCache();
                    notifyChangedExternally();
                  }

                  @Override
                  public void redo() {
                    dropCache();
                    notifyChangedExternally();
                  }
                });
      }
    }.execute();
  }
  private void annotateExternally(
      @NotNull final VirtualFile file,
      @NotNull final PsiModifierListOwner listOwner,
      @NotNull Project project,
      @NotNull final String packageName,
      final VirtualFile virtualFile,
      @NotNull final String annotationFQName,
      @NotNull final PsiFile fromFile,
      final PsiNameValuePair[] value) {
    final XmlFile[] annotationsXml = new XmlFile[1];
    List<XmlFile> xmlFiles = findExternalAnnotationsXmlFiles(listOwner);
    if (xmlFiles != null) {
      for (XmlFile xmlFile : xmlFiles) {
        final VirtualFile vXmlFile = xmlFile.getVirtualFile();
        assert vXmlFile != null;
        if (VfsUtilCore.isAncestor(file, vXmlFile, false)) {
          annotationsXml[0] = xmlFile;
          if (!CodeInsightUtilBase.preparePsiElementForWrite(xmlFile)) return;
        }
      }
    } else {
      xmlFiles = new ArrayList<XmlFile>();
    }

    final List<PsiFile> annotationFiles = new ArrayList<PsiFile>(xmlFiles);
    new WriteCommandAction(project) {
      @Override
      protected void run(final Result result) throws Throwable {
        if (annotationsXml[0] == null) {
          annotationsXml[0] = createAnnotationsXml(file, packageName);
        }
        if (annotationsXml[0] != null) {
          annotationFiles.add(annotationsXml[0]);
          myExternalAnnotations.put(getFQN(packageName, virtualFile), annotationFiles);
          annotateExternally(listOwner, annotationFQName, annotationsXml[0], fromFile, value);
        }
      }
    }.execute();

    UndoManager.getInstance(project)
        .undoableActionPerformed(
            new BasicUndoableAction() {
              @Override
              public void undo() throws UnexpectedUndoException {
                dropCache();
              }

              @Override
              public void redo() throws UnexpectedUndoException {
                dropCache();
              }
            });
  }