private boolean isLocalBranch(Git git, String branch) throws GitAPIException {
   List<Ref> branches = git.branchList().call();
   for (Ref ref : branches) {
     if (Repository.shortenRefName(ref.getName()).equals(branch)) return true;
   }
   return false;
 }
  /**
   * remove highlights (bounded with <marker>...</marker>) from test case file
   *
   * @param document document to process
   */
  private void extractExpectedHighlightsSet(final Document document) {
    final String text = document.getText();

    final Set<String> markers = myHighlightingTypes.keySet();
    final String typesRx = "(?:" + StringUtil.join(markers, ")|(?:") + ")";
    final String openingTagRx =
        "<("
            + typesRx
            + ")"
            + "(?:\\s+descr=\"((?:[^\"]|\\\\\"|\\\\\\\\\"|\\\\\\[|\\\\\\])*)\")?"
            + "(?:\\s+type=\"([0-9A-Z_]+)\")?"
            + "(?:\\s+foreground=\"([0-9xa-f]+)\")?"
            + "(?:\\s+background=\"([0-9xa-f]+)\")?"
            + "(?:\\s+effectcolor=\"([0-9xa-f]+)\")?"
            + "(?:\\s+effecttype=\"([A-Z]+)\")?"
            + "(?:\\s+fonttype=\"([0-9]+)\")?"
            + "(?:\\s+textAttributesKey=\"((?:[^\"]|\\\\\"|\\\\\\\\\"|\\\\\\[|\\\\\\])*)\")?"
            + "(?:\\s+bundleMsg=\"((?:[^\"]|\\\\\"|\\\\\\\\\")*)\")?"
            + "(/)?>";

    final Matcher matcher = Pattern.compile(openingTagRx).matcher(text);
    int pos = 0;
    final Ref<Integer> textOffset = Ref.create(0);
    while (matcher.find(pos)) {
      textOffset.set(textOffset.get() + matcher.start() - pos);
      pos = extractExpectedHighlight(matcher, text, document, textOffset);
    }
  }
  @Nullable
  private FilePath unshelveBinaryFile(
      final ShelvedBinaryFile file, @NotNull final VirtualFile patchTarget) throws IOException {
    final Ref<FilePath> result = new Ref<FilePath>();
    final Ref<IOException> ex = new Ref<IOException>();
    final Ref<VirtualFile> patchedFileRef = new Ref<VirtualFile>();
    final File shelvedFile = file.SHELVED_PATH == null ? null : new File(file.SHELVED_PATH);

    ApplicationManager.getApplication()
        .runWriteAction(
            new Runnable() {
              public void run() {
                try {
                  result.set(new FilePathImpl(patchTarget));
                  if (shelvedFile == null) {
                    patchTarget.delete(this);
                  } else {
                    patchTarget.setBinaryContent(FileUtil.loadFileBytes(shelvedFile));
                    patchedFileRef.set(patchTarget);
                  }
                } catch (IOException e) {
                  ex.set(e);
                }
              }
            });
    if (!ex.isNull()) {
      throw ex.get();
    }
    return result.get();
  }
  public boolean navigateSelectedElement() {
    final Ref<Boolean> succeeded = new Ref<Boolean>();
    final CommandProcessor commandProcessor = CommandProcessor.getInstance();
    commandProcessor.executeCommand(
        myProject,
        new Runnable() {
          public void run() {
            final AbstractTreeNode selectedNode = getSelectedNode();
            if (selectedNode != null) {
              if (selectedNode.canNavigateToSource()) {
                myPopup.cancel();
                selectedNode.navigate(true);
                succeeded.set(true);
              } else {
                succeeded.set(false);
              }
            } else {
              succeeded.set(false);
            }

            IdeDocumentHistory.getInstance(myProject).includeCurrentCommandAsNavigation();
          }
        },
        "Navigate",
        null);
    return succeeded.get();
  }
  private boolean cherryPick(
      HttpServletRequest request,
      HttpServletResponse response,
      Repository db,
      String commitToCherryPick)
      throws ServletException, JSONException {
    RevWalk revWalk = new RevWalk(db);
    try {

      Ref headRef = db.getRef(Constants.HEAD);
      if (headRef == null)
        return statusHandler.handleRequest(
            request,
            response,
            new ServerStatus(
                IStatus.ERROR,
                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                "An error occured when cherry-picking.",
                null));
      RevCommit head = revWalk.parseCommit(headRef.getObjectId());

      ObjectId objectId = db.resolve(commitToCherryPick);
      Git git = new Git(db);
      CherryPickResult cherryPickResult = git.cherryPick().include(objectId).call();
      RevCommit newHead = cherryPickResult.getNewHead();

      JSONObject result = new JSONObject();
      result.put(GitConstants.KEY_RESULT, cherryPickResult.getStatus().name());
      result.put(GitConstants.KEY_HEAD_UPDATED, !head.equals(newHead));
      OrionServlet.writeJSONResponse(
          request, response, result, JsonURIUnqualificationStrategy.ALL_NO_GIT);
      return true;
    } catch (IOException e) {
      return statusHandler.handleRequest(
          request,
          response,
          new ServerStatus(
              IStatus.ERROR,
              HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
              "An error occured when cherry-picking.",
              e));
    } catch (GitAPIException e) {
      return statusHandler.handleRequest(
          request,
          response,
          new ServerStatus(
              IStatus.ERROR,
              HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
              "An error occured when cherry-picking.",
              e));
    } finally {
      revWalk.release();
    }
  }
 @Override
 public <T> T commitAndRunReadAction(@NotNull final Computable<T> computation) {
   final Ref<T> ref = Ref.create(null);
   commitAndRunReadAction(
       new Runnable() {
         @Override
         public void run() {
           ref.set(computation.compute());
         }
       });
   return ref.get();
 }
Beispiel #7
0
 /**
  * Constructs a <code>SerialRef</code> object from the given <code>Ref</code> object.
  *
  * @param ref a Ref object; cannot be <code>null</code>
  * @throws SQLException if a database access occurs; if <code>ref</code> is <code>null</code>; or
  *     if the <code>Ref</code> object returns a <code>null</code> value base type name.
  * @throws SerialException if an error occurs serializing the <code>Ref</code> object
  */
 public SerialRef(Ref ref) throws SerialException, SQLException {
   if (ref == null) {
     throw new SQLException("Cannot instantiate a SerialRef object " + "with a null Ref object");
   }
   reference = ref;
   object = ref;
   if (ref.getBaseTypeName() == null) {
     throw new SQLException(
         "Cannot instantiate a SerialRef object " + "that returns a null base type name");
   } else {
     baseTypeName = new String(ref.getBaseTypeName());
   }
 }
  public void getServerFilesManagers(
      final Ref<SvnServerFileManager> systemManager, final Ref<SvnServerFileManager> userManager) {
    // created only if does not exist
    final File dir = new File(getConfigurationDirectory());
    if (!dir.exists()) {
      SVNConfigFile.createDefaultConfiguration(dir);
    }

    systemManager.set(
        new SvnServerFileManagerImpl(
            new IdeaSVNConfigFile(
                new File(SVNFileUtil.getSystemConfigurationDirectory(), SERVERS_FILE_NAME))));
    initServers();
    userManager.set(new SvnServerFileManagerImpl(myConfigFile));
  }
Beispiel #9
0
  // returns the most recent val
  Object lock(Ref ref) {
    // can't upgrade readLock, so release it
    releaseIfEnsured(ref);

    boolean unlocked = true;
    try {
      tryWriteLock(ref);
      unlocked = false;

      if (ref.tvals != null && ref.tvals.point > readPoint) throw retryex;
      Info refinfo = ref.tinfo;

      // write lock conflict
      if (refinfo != null && refinfo != info && refinfo.running()) {
        if (!barge(refinfo)) {
          ref.lock.writeLock().unlock();
          unlocked = true;
          return blockAndBail(refinfo);
        }
      }
      ref.tinfo = info;
      return ref.tvals == null ? null : ref.tvals.val;
    } finally {
      if (!unlocked) ref.lock.writeLock().unlock();
    }
  }
 private static TextRange adjustRange(final PsiElement element, final TextRange originalRange) {
   final Ref<TextRange> rangeRef = new Ref<TextRange>(originalRange);
   element.accept(
       new JavaRecursiveElementVisitor() {
         @Override
         public void visitExpressionStatement(final PsiExpressionStatement statement) {
           final TextRange stRange = statement.getTextRange();
           if (originalRange.intersects(stRange)) {
             final TextRange currentRange = rangeRef.get();
             final int start = Math.min(currentRange.getStartOffset(), stRange.getStartOffset());
             final int end = Math.max(currentRange.getEndOffset(), stRange.getEndOffset());
             rangeRef.set(new TextRange(start, end));
           }
         }
       });
   return rangeRef.get();
 }
Beispiel #11
0
 /**
  * Sets the SQL structured type that this <code>SerialRef</code> object references to the given
  * <code>Object</code> object.
  *
  * @param obj an <code>Object</code> representing the SQL structured type to be referenced
  * @throws SerialException if an error is encountered generating the the structured type
  *     referenced by this <code>SerialRef</code> object
  */
 public void setObject(Object obj) throws SerialException {
   try {
     reference.setObject(obj);
   } catch (SQLException e) {
     throw new SerialException("SQLException: " + e.getMessage());
   }
   object = obj;
 }
  @Nullable
  public static PsiType getQualifiedMemberReferenceType(
      @Nullable PsiType qualifierType, @NotNull final PsiMember member) {
    final Ref<PsiSubstitutor> subst = Ref.create(PsiSubstitutor.EMPTY);
    class MyProcessor extends BaseScopeProcessor implements NameHint, ElementClassHint {
      @Override
      public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) {
        if (element == member) {
          subst.set(state.get(PsiSubstitutor.KEY));
        }
        return true;
      }

      @Override
      public String getName(@NotNull ResolveState state) {
        return member.getName();
      }

      @Override
      public boolean shouldProcess(DeclarationKind kind) {
        return member instanceof PsiEnumConstant
            ? kind == DeclarationKind.ENUM_CONST
            : member instanceof PsiField
                ? kind == DeclarationKind.FIELD
                : kind == DeclarationKind.METHOD;
      }

      @Override
      public <T> T getHint(@NotNull Key<T> hintKey) {
        return hintKey == NameHint.KEY || hintKey == ElementClassHint.KEY ? (T) this : null;
      }
    }

    PsiScopesUtil.processTypeDeclarations(qualifierType, member, new MyProcessor());

    PsiType rawType =
        member instanceof PsiField
            ? ((PsiField) member).getType()
            : member instanceof PsiMethod
                ? ((PsiMethod) member).getReturnType()
                : JavaPsiFacade.getElementFactory(member.getProject())
                    .createType((PsiClass) member);
    return subst.get().substitute(rawType);
  }
  protected static RevCommit resolveCommitIdByTagName(Repository repository, String tagName)
      throws IOException, GitAPIException {
    if (tagName == null || tagName.isEmpty()) return null;
    RevCommit revCommit = null;
    Map<String, Ref> tagMap = repository.getTags();
    Ref ref = tagMap.get(tagName);
    if (ref != null) {
      RevWalk walk = new RevWalk(repository);
      // some reduce memory effors as described in jgit user guide
      walk.setRetainBody(false);
      ObjectId from;

      from = repository.resolve("refs/heads/master");
      if (from == null) {
        Git git = new Git(repository);
        String lastTagName = git.describe().call();
        from = repository.resolve("refs/tags/" + lastTagName);
      }
      ObjectId to = repository.resolve("refs/remotes/origin/master");

      if (from == null) {
        throw new IllegalStateException("cannot determinate start commit");
      }
      walk.markStart(walk.parseCommit(from));
      walk.markUninteresting(walk.parseCommit(to));
      try {

        RevObject revObject = walk.parseAny(ref.getObjectId());
        if (revObject != null) {
          revCommit = walk.parseCommit(revObject.getId());
        }

      } finally {
        walk.close();
      }
    }

    return revCommit;
  }
 public void openFiles() {
   if (mySplittersElement != null) {
     Ref<EditorWindow> currentWindow = new Ref<EditorWindow>();
     final JPanel comp = readExternalPanel(mySplittersElement, getTopPanel(), currentWindow);
     if (comp != null) {
       removeAll();
       add(comp, BorderLayout.CENTER);
       mySplittersElement = null;
     }
     // clear empty splitters
     for (EditorWindow window : getWindows()) {
       if (window.getEditors().length == 0) {
         for (EditorWindow sibling : window.findSiblings()) {
           sibling.unsplit(false);
         }
       }
     }
     if (!currentWindow.isNull()) {
       setCurrentWindow(currentWindow.get(), true);
     }
   }
 }
Beispiel #15
0
  /**
   * Returns an <code>Object</code> representing the SQL structured type to which this <code>
   * SerialRef</code> object refers.
   *
   * @return an object instance resolved from the Ref reference
   * @throws SerialException if an error is encountered in the reference resolution
   */
  public Object getObject() throws SerialException {

    if (reference != null) {
      try {
        return reference.getObject();
      } catch (SQLException e) {
        throw new SerialException("SQLException: " + e.getMessage());
      }
    }

    if (object != null) {
      return object;
    }

    throw new SerialException("The object is not set");
  }
Beispiel #16
0
 Object doGet(Ref ref) {
   if (!info.running()) throw retryex;
   if (vals.containsKey(ref)) return vals.get(ref);
   try {
     ref.lock.readLock().lock();
     if (ref.tvals == null) throw new IllegalStateException(ref.toString() + " is unbound.");
     Ref.TVal ver = ref.tvals;
     do {
       if (ver.point <= readPoint) return ver.val;
     } while ((ver = ver.prior) != ref.tvals);
   } finally {
     ref.lock.readLock().unlock();
   }
   // no version of val precedes the read point
   ref.faults.incrementAndGet();
   throw retryex;
 }
 @Override
 protected JPanel processSplitter(
     @NotNull Element splitterElement,
     Element firstChild,
     Element secondChild,
     final JPanel context) {
   if (context == null) {
     final boolean orientation =
         "vertical".equals(splitterElement.getAttributeValue("split-orientation"));
     final float proportion =
         Float.valueOf(splitterElement.getAttributeValue("split-proportion")).floatValue();
     final JPanel firstComponent = process(firstChild, null);
     final JPanel secondComponent = process(secondChild, null);
     final Ref<JPanel> panelRef = new Ref<JPanel>();
     UIUtil.invokeAndWaitIfNeeded(
         new Runnable() {
           @Override
           public void run() {
             JPanel panel = new JPanel(new BorderLayout());
             panel.setOpaque(false);
             Splitter splitter = new OnePixelSplitter(orientation, proportion, 0.1f, 0.9f);
             panel.add(splitter, BorderLayout.CENTER);
             splitter.setFirstComponent(firstComponent);
             splitter.setSecondComponent(secondComponent);
             panelRef.set(panel);
           }
         });
     return panelRef.get();
   }
   final Ref<JPanel> firstComponent = new Ref<JPanel>();
   final Ref<JPanel> secondComponent = new Ref<JPanel>();
   UIUtil.invokeAndWaitIfNeeded(
       new Runnable() {
         @Override
         public void run() {
           if (context.getComponent(0) instanceof Splitter) {
             Splitter splitter = (Splitter) context.getComponent(0);
             firstComponent.set((JPanel) splitter.getFirstComponent());
             secondComponent.set((JPanel) splitter.getSecondComponent());
           } else {
             firstComponent.set(context);
             secondComponent.set(context);
           }
         }
       });
   process(firstChild, firstComponent.get());
   process(secondChild, secondComponent.get());
   return context;
 }
    @Override
    protected JPanel processFiles(@NotNull List<Element> fileElements, final JPanel context) {
      final Ref<EditorWindow> windowRef = new Ref<EditorWindow>();
      UIUtil.invokeAndWaitIfNeeded(
          new Runnable() {
            @Override
            public void run() {
              windowRef.set(context == null ? createEditorWindow() : findWindowWith(context));
            }
          });
      final EditorWindow window = windowRef.get();
      LOG.assertTrue(window != null);
      VirtualFile focusedFile = null;

      for (int i = 0; i < fileElements.size(); i++) {
        final Element file = fileElements.get(i);
        if (i == 0) {
          EditorTabbedContainer tabbedPane = window.getTabbedPane();
          if (tabbedPane != null) {
            try {
              int limit =
                  Integer.parseInt(
                      file.getParentElement()
                          .getAttributeValue(
                              JBTabsImpl.SIDE_TABS_SIZE_LIMIT_KEY.toString(),
                              String.valueOf(JBTabsImpl.DEFAULT_MAX_TAB_WIDTH)));
              UIUtil.putClientProperty(
                  tabbedPane.getComponent(), JBTabsImpl.SIDE_TABS_SIZE_LIMIT_KEY, limit);
            } catch (NumberFormatException e) {
              // ignore
            }
          }
        }
        try {
          final FileEditorManagerImpl fileEditorManager = getManager();
          Element historyElement = file.getChild(HistoryEntry.TAG);
          final HistoryEntry entry =
              HistoryEntry.createLight(fileEditorManager.getProject(), historyElement);
          final VirtualFile virtualFile = entry.getFile();
          if (virtualFile == null)
            throw new InvalidDataException("No file exists: " + entry.getFilePointer().getUrl());
          Document document =
              ApplicationManager.getApplication()
                  .runReadAction(
                      new Computable<Document>() {
                        @Override
                        public Document compute() {
                          return virtualFile.isValid()
                              ? FileDocumentManager.getInstance().getDocument(virtualFile)
                              : null;
                        }
                      });
          final boolean isCurrentInTab =
              Boolean.valueOf(file.getAttributeValue(CURRENT_IN_TAB)).booleanValue();
          Boolean pin = Boolean.valueOf(file.getAttributeValue(PINNED));
          fileEditorManager.openFileImpl4(
              window, virtualFile, entry, isCurrentInTab, isCurrentInTab, pin, i);
          if (isCurrentInTab) {
            focusedFile = virtualFile;
          }
          if (document != null) {
            // This is just to make sure document reference is kept on stack till this point
            // so that document is available for folding state deserialization in HistoryEntry
            // constructor
            // and that document will be created only once during file opening
            document.putUserData(DUMMY_KEY, null);
          }
          updateProgress();
        } catch (InvalidDataException e) {
          if (ApplicationManager.getApplication().isUnitTestMode()) {
            LOG.error(e);
          }
        }
      }
      if (focusedFile != null) {
        getManager().addSelectionRecord(focusedFile, window);
      }
      return window.myPanel;
    }
  private void buildOutputItemsList(
      final String outputDir,
      final Module module,
      VirtualFile from,
      final FileTypeManager typeManager,
      final VirtualFile sourceRoot,
      final String packagePrefix,
      final List<File> filesToRefresh,
      final Map<String, Collection<TranslatingCompiler.OutputItem>> results)
      throws CacheCorruptedException {
    final Ref<CacheCorruptedException> exRef = new Ref<CacheCorruptedException>(null);
    final ModuleFileIndex fileIndex = ModuleRootManager.getInstance(module).getFileIndex();
    final GlobalSearchScope srcRootScope =
        GlobalSearchScope.moduleScope(module)
            .intersectWith(GlobalSearchScopes.directoryScope(myProject, sourceRoot, true));

    final Collection<FileType> registeredInputTypes =
        CompilerManager.getInstance(myProject).getRegisteredInputTypes(myTranslatingCompiler);

    final ContentIterator contentIterator =
        new ContentIterator() {
          public boolean processFile(final VirtualFile child) {
            try {
              if (child.isValid()) {
                if (!child.isDirectory() && registeredInputTypes.contains(child.getFileType())) {
                  updateOutputItemsList(
                      outputDir,
                      child,
                      sourceRoot,
                      packagePrefix,
                      filesToRefresh,
                      results,
                      srcRootScope);
                }
              }
              return true;
            } catch (CacheCorruptedException e) {
              exRef.set(e);
              return false;
            }
          }
        };
    if (fileIndex.isInContent(from)) {
      // use file index for iteration to handle 'inner modules' and excludes properly
      fileIndex.iterateContentUnderDirectory(from, contentIterator);
    } else {
      // seems to be a root for generated sources
      VfsUtilCore.visitChildrenRecursively(
          from,
          new VirtualFileVisitor() {
            @Override
            public boolean visitFile(@NotNull VirtualFile file) {
              if (!file.isDirectory()) {
                contentIterator.processFile(file);
              }
              return true;
            }
          });
    }
    final CacheCorruptedException exc = exRef.get();
    if (exc != null) {
      throw exc;
    }
  }
  private int extractExpectedHighlight(
      final Matcher matcher,
      final String text,
      final Document document,
      final Ref<Integer> textOffset) {
    document.deleteString(textOffset.get(), textOffset.get() + matcher.end() - matcher.start());

    int groupIdx = 1;
    final String marker = matcher.group(groupIdx++);
    String descr = matcher.group(groupIdx++);
    final String typeString = matcher.group(groupIdx++);
    final String foregroundColor = matcher.group(groupIdx++);
    final String backgroundColor = matcher.group(groupIdx++);
    final String effectColor = matcher.group(groupIdx++);
    final String effectType = matcher.group(groupIdx++);
    final String fontType = matcher.group(groupIdx++);
    final String attrKey = matcher.group(groupIdx++);
    final String bundleMessage = matcher.group(groupIdx++);
    final boolean closed = matcher.group(groupIdx) != null;

    if (descr == null) {
      descr = ANY_TEXT; // no descr means any string by default
    } else if (descr.equals("null")) {
      descr = null; // explicit "null" descr
    }
    if (descr != null) {
      descr =
          descr.replaceAll(
              "\\\\\\\\\"", "\""); // replace: \\" to ", doesn't check symbol before sequence \\"
      descr = descr.replaceAll("\\\\\"", "\"");
    }

    HighlightInfoType type = WHATEVER;
    if (typeString != null) {
      try {
        type = getTypeByName(typeString);
      } catch (Exception e) {
        LOG.error(e);
      }
      LOG.assertTrue(type != null, "Wrong highlight type: " + typeString);
    }

    TextAttributes forcedAttributes = null;
    if (foregroundColor != null) {
      //noinspection MagicConstant
      forcedAttributes =
          new TextAttributes(
              Color.decode(foregroundColor),
              Color.decode(backgroundColor),
              Color.decode(effectColor),
              EffectType.valueOf(effectType),
              Integer.parseInt(fontType));
    }

    final int rangeStart = textOffset.get();
    final int toContinueFrom;
    if (closed) {
      toContinueFrom = matcher.end();
    } else {
      int pos = matcher.end();
      final Matcher closingTagMatcher = Pattern.compile("</" + marker + ">").matcher(text);
      while (true) {
        if (!closingTagMatcher.find(pos)) {
          LOG.error("Cannot find closing </" + marker + "> in position " + pos);
        }

        final int nextTagStart = matcher.find(pos) ? matcher.start() : text.length();
        if (closingTagMatcher.start() < nextTagStart) {
          textOffset.set(textOffset.get() + closingTagMatcher.start() - pos);
          document.deleteString(
              textOffset.get(),
              textOffset.get() + closingTagMatcher.end() - closingTagMatcher.start());
          toContinueFrom = closingTagMatcher.end();
          break;
        }

        textOffset.set(textOffset.get() + nextTagStart - pos);
        pos = extractExpectedHighlight(matcher, text, document, textOffset);
      }
    }

    final ExpectedHighlightingSet expectedHighlightingSet = myHighlightingTypes.get(marker);
    if (expectedHighlightingSet.enabled) {
      TextAttributesKey forcedTextAttributesKey =
          attrKey == null ? null : TextAttributesKey.createTextAttributesKey(attrKey);
      HighlightInfo.Builder builder =
          HighlightInfo.newHighlightInfo(type)
              .range(rangeStart, textOffset.get())
              .severity(expectedHighlightingSet.severity);

      if (forcedAttributes != null) builder.textAttributes(forcedAttributes);
      if (forcedTextAttributesKey != null) builder.textAttributes(forcedTextAttributesKey);
      if (bundleMessage != null) {
        final List<String> split = StringUtil.split(bundleMessage, "|");
        final ResourceBundle bundle = ResourceBundle.getBundle(split.get(0));
        descr = CommonBundle.message(bundle, split.get(1), split.stream().skip(2).toArray());
      }
      if (descr != null) {
        builder.description(descr);
        builder.unescapedToolTip(descr);
      }
      if (expectedHighlightingSet.endOfLine) builder.endOfLine();
      HighlightInfo highlightInfo = builder.createUnconditionally();
      expectedHighlightingSet.infos.add(highlightInfo);
    }

    return toContinueFrom;
  }
Beispiel #21
0
  Object run(Callable fn) throws Exception {
    boolean done = false;
    Object ret = null;
    ArrayList<Ref> locked = new ArrayList<Ref>();
    ArrayList<Notify> notify = new ArrayList<Notify>();

    for (int i = 0; !done && i < RETRY_LIMIT; i++) {
      try {
        getReadPoint();
        if (i == 0) {
          startPoint = readPoint;
          startTime = System.nanoTime();
        }
        info = new Info(RUNNING, startPoint);
        ret = fn.call();
        // make sure no one has killed us before this point, and can't from now on
        if (info.status.compareAndSet(RUNNING, COMMITTING)) {
          for (Map.Entry<Ref, ArrayList<CFn>> e : commutes.entrySet()) {
            Ref ref = e.getKey();
            if (sets.contains(ref)) continue;

            boolean wasEnsured = ensures.contains(ref);
            // can't upgrade readLock, so release it
            releaseIfEnsured(ref);
            tryWriteLock(ref);
            locked.add(ref);
            if (wasEnsured && ref.tvals != null && ref.tvals.point > readPoint) throw retryex;

            Info refinfo = ref.tinfo;
            if (refinfo != null && refinfo != info && refinfo.running()) {
              if (!barge(refinfo)) throw retryex;
            }
            Object val = ref.tvals == null ? null : ref.tvals.val;
            vals.put(ref, val);
            for (CFn f : e.getValue()) {
              vals.put(ref, f.fn.applyTo(RT.cons(vals.get(ref), f.args)));
            }
          }
          for (Ref ref : sets) {
            tryWriteLock(ref);
            locked.add(ref);
          }

          // validate and enqueue notifications
          for (Map.Entry<Ref, Object> e : vals.entrySet()) {
            Ref ref = e.getKey();
            ref.validate(ref.getValidator(), e.getValue());
          }

          // at this point, all values calced, all refs to be written locked
          // no more client code to be called
          long commitPoint = getCommitPoint();
          for (Map.Entry<Ref, Object> e : vals.entrySet()) {
            Ref ref = e.getKey();
            Object oldval = ref.tvals == null ? null : ref.tvals.val;
            Object newval = e.getValue();
            int hcount = ref.histCount();

            if (ref.tvals == null) {
              ref.tvals = new Ref.TVal(newval, commitPoint);
            } else if ((ref.faults.get() > 0 && hcount < ref.maxHistory)
                || hcount < ref.minHistory) {
              ref.tvals = new Ref.TVal(newval, commitPoint, ref.tvals);
              ref.faults.set(0);
            } else {
              ref.tvals = ref.tvals.next;
              ref.tvals.val = newval;
              ref.tvals.point = commitPoint;
            }
            if (ref.getWatches().count() > 0) notify.add(new Notify(ref, oldval, newval));
          }

          done = true;
          info.status.set(COMMITTED);
        }
      } catch (RetryEx retry) {
        // eat this so we retry rather than fall out
      } finally {
        for (int k = locked.size() - 1; k >= 0; --k) {
          locked.get(k).lock.writeLock().unlock();
        }
        locked.clear();
        for (Ref r : ensures) {
          r.lock.readLock().unlock();
        }
        ensures.clear();
        stop(done ? COMMITTED : RETRY);
        try {
          if (done) // re-dispatch out of transaction
          {
            for (Notify n : notify) {
              n.ref.notifyWatches(n.oldval, n.newval);
            }
            for (Agent.Action action : actions) {
              Agent.dispatchAction(action);
            }
          }
        } finally {
          notify.clear();
          actions.clear();
        }
      }
    }
    if (!done) throw Util.runtimeException("Transaction failed after reaching retry limit");
    return ret;
  }