private void handleEnrollInTransaction(Operation request) {
      String serviceSelfLink = this.service.getSelfLink();
      if (Action.POST == request.getAction()) {
        ServiceDocument body = request.getBody(this.service.getStateType());
        if (body.documentSelfLink == null) {
          body.documentSelfLink = UUID.randomUUID().toString();
          request.setBody(body);
        }
        serviceSelfLink = UriUtils.buildUriPath(serviceSelfLink, body.documentSelfLink);
      }

      long servicePreviousVersion =
          this.service.getState(request) == null
              ? -1
              : this.service.getState(request).documentVersion;
      Operation enrollRequest =
          SimpleTransactionService.TxUtils.buildEnrollRequest(
                  this.service.getHost(),
                  request.getTransactionId(),
                  serviceSelfLink,
                  request.getAction(),
                  servicePreviousVersion)
              .setCompletion(
                  (o, e) -> {
                    if (e != null) {
                      request.fail(e);
                      return;
                    }
                    this.service
                        .getOperationProcessingChain()
                        .resumeProcessingRequest(request, this);
                  });
      this.service.sendRequest(enrollRequest);
    }
    private boolean validateTransactionConflictsAndMarkState(
        Operation request, ServiceDocument currentState) {
      if (currentState == null) {
        return false;
      }

      String requestTransactionId = request.getTransactionId();
      String currentStateTransactionId = currentState.documentTransactionId;

      if (request.getAction() == Action.GET) {
        if (requestTransactionId == null) {
          // non-transactional read
          if (currentStateTransactionId == null) {
            return false;
          } else {
            logTransactionConflict(request, currentState);
            return true;
          }
        } else {
          // transactional read
          if (currentStateTransactionId == null) {
            logTransactionUpdate(buildLogTransactionUpdateMsg(request, currentState));
            currentState.documentTransactionId = requestTransactionId;
            return false;
          } else {
            if (requestTransactionId.equals(currentStateTransactionId)) {
              return false;
            } else {
              logTransactionConflict(request, currentState);
              return true;
            }
          }
        }
      } else {
        if (requestTransactionId == null) {
          // non-transactional write
          if (currentStateTransactionId == null
              || request.hasPragmaDirective(PRAGMA_DIRECTIVE_DELETE_ON_TRANSACTION_END)) {
            return false;
          } else {
            logTransactionConflict(request, currentState);
            return true;
          }
        } else {
          // transactional write
          if (currentStateTransactionId == null) {
            logTransactionUpdate(buildLogTransactionUpdateMsg(request, currentState));
            currentState.documentTransactionId = requestTransactionId;
            return false;
          } else {
            if (requestTransactionId.equals(currentStateTransactionId)) {
              return false;
            } else {
              logTransactionConflict(request, currentState);
              return true;
            }
          }
        }
      }
    }
Example #3
0
  @Override
  public void handlePut(Operation op) {
    if (!op.hasBody()) {
      op.fail(new IllegalArgumentException("body is required"));
      return;
    }

    RoleState newState = op.getBody(RoleState.class);
    if (!validate(op, newState)) {
      return;
    }

    RoleState currentState = getState(op);
    ServiceDocumentDescription documentDescription = this.getDocumentTemplate().documentDescription;
    if (ServiceDocument.equals(documentDescription, currentState, newState)) {
      op.setStatusCode(Operation.STATUS_CODE_NOT_MODIFIED);
    } else {
      setState(op, newState);
    }

    op.complete();
  }
    private void handleClearTransaction(
        Operation request,
        ServiceDocument currentState,
        ClearTransactionRequest clearTransactionRequest) {
      if (currentState == null) {
        request.complete();
        return;
      }

      if (!request.getTransactionId().equals(currentState.documentTransactionId)) {
        if (clearTransactionRequest.transactionOutcome == TransactionOutcome.COMMIT) {
          String warning =
              String.format(
                  "Request to clear transaction %s from service %s but current transaction is: %s",
                  request.getTransactionId(),
                  this.service.getSelfLink(),
                  currentState.documentTransactionId);
          this.service.getHost().log(Level.WARNING, warning);
        }
        request.complete();
        return;
      }

      if (clearTransactionRequest.transactionOutcome == TransactionOutcome.ABORT
          && clearTransactionRequest.isUpdated) {
        // restore previous state
        URI previousStateQueryUri =
            UriUtils.buildDocumentQueryUri(
                this.service.getHost(),
                this.service.getSelfLink(),
                false,
                false,
                ServiceOption.PERSISTENCE);
        previousStateQueryUri =
            UriUtils.appendQueryParam(
                previousStateQueryUri,
                ServiceDocument.FIELD_NAME_VERSION,
                Long.toString(clearTransactionRequest.originalVersion));
        Operation previousStateGet =
            Operation.createGet(previousStateQueryUri)
                .setCompletion(
                    (o, e) -> {
                      if (e != null) {
                        request.fail(e);
                        return;
                      }
                      ServiceDocument previousState = o.getBody(currentState.getClass());
                      this.service
                          .getHost()
                          .log(
                              Level.INFO,
                              "Aborting transaction %s on service %s, current version %d, restoring version %d",
                              request.getTransactionId(),
                              this.service.getSelfLink(),
                              currentState.documentVersion,
                              clearTransactionRequest.originalVersion);
                      previousState.documentTransactionId = null;
                      this.service.setState(request, previousState);
                      request.complete();
                    });
        this.service.sendRequest(previousStateGet);
        return;
      }

      currentState.documentTransactionId = null;
      request.complete();
    }