Repository Handlers and Commit Processing

 

Author: Eike Stepper

Repository handlers are the focused supported interception points for application behavior. They are not a reason to implement a store. Install a handler with IRepository.addHandler(IRepository.Handler) and remove that same instance when the owning extension stops.

1 Read and Write Access
2 Commit Information and Conflicts
3 Application-facing Commit Flow

1  Read and Write Access

A ReadAccessHandler receives the exact requested revisions and a separate list of optimizer-supplied additional revisions. If any requested revision is forbidden, throw to reject the request; the handler cannot silently remove only part of that array. It may remove speculative additional revisions that the client did not request. Keep checks bounded because they execute on the read path.

A WriteAccessHandler runs before a transaction reaches the store and, after a successful persistence, again in its after-commit callback. The before callback receives the server transaction, commit context, and progress monitor. Use WriteAccessHandler.TransactionValidationException for semantic validation; its message is returned to the client. The commit context is for inspection; if a supported mutation is needed, use its documented modify(...) operation rather than altering its internal state directly. The after callback is observation-only and must not mutate the context. Both callbacks are on the commit path and should avoid slow work. ObjectWriteAccessHandler is the supported SPI base for object-level write checks.

2  Commit Information and Conflicts

A write handler's after-commit callback observes the specific transaction and commit context immediately after its store commit. A CDOCommitInfoHandler registered with the repository's commit-info manager observes completed commit-info records, which is a better seam for indexing or auditing that is organized around commit metadata. Neither callback should perform unbounded work inline; copy the required immutable values and submit expensive processing to an application executor. ICommitConflictResolver is an expert SPI for resolving eligible transaction conflicts and is configured as part of repository setup. Its contract exposes commit-context SPI, so use it only when policy cannot be expressed through ordinary validation and client conflict handling.

3  Application-facing Commit Flow

A client transaction arrives with authenticated session and transaction context. Repository protection and authorization decide whether the user may read or write; before-commit handlers apply application validation; conflict policy handles eligible concurrent changes; and the configured store persists the accepted change. The repository then publishes commit information and update notifications, while after-commit handlers observe the result. These are conceptual application phases; exact signal and store-internal sequencing is not a contract. The snippets show a read gate, a validation rule, and completed-commit observation.

Read check: InstallReadCheck.java      
ReadAccessHandler handler = new ReadAccessHandler()
{
  @Override
  public void handleRevisionsBeforeSending(ISession session, CDORevision[] revisions, List<CDORevision> additionalRevisions)
  {
    if (session.getUserID() == null)
    {
      throw new SecurityException("Authentication is required");
    }
  }
};

repository.addHandler(handler);
return handler;

Semantic validation: RequireCommitComment.java      
WriteAccessHandler handler = new WriteAccessHandler()
{
  @Override
  public void handleTransactionBeforeCommitting(ITransaction transaction, IStoreAccessor.CommitContext commitContext, OMMonitor monitor)
  {
    String comment = commitContext.getCommitComment();
    if (comment == null || comment.trim().isEmpty())
    {
      throw new TransactionValidationException("A commit comment is required");
    }
  }

  @Override
  public void handleTransactionAfterCommitted(ITransaction transaction, IStoreAccessor.CommitContext commitContext, OMMonitor monitor)
  {
    // Keep the after-commit callback observation-only and quick.
  }
};

repository.addHandler(handler);
return handler;

Commit observation: ObserveCommitInfo.java      
CDOCommitInfoHandler handler = enqueue::accept;
repository.getCommitInfoManager().addCommitInfoHandler(handler);
return handler;