All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.sqlclient.impl.TransactionImpl Maven / Gradle / Ivy

There is a newer version: 5.0.0.CR3
Show newest version
/*
 * Copyright (C) 2017 Julien Viet
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package io.vertx.sqlclient.impl;

import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.impl.ContextInternal;
import io.vertx.core.impl.future.PromiseInternal;
import io.vertx.sqlclient.Transaction;
import io.vertx.sqlclient.TransactionRollbackException;
import io.vertx.sqlclient.impl.command.CommandBase;
import io.vertx.sqlclient.impl.command.TxCommand;

public class TransactionImpl implements Transaction {

  private final ContextInternal context;
  private final Connection connection;
  private final Promise completion;
  private final Handler endHandler;
  private int pendingQueries;
  private boolean ended;
  private boolean failed;
  private TxCommand endCommand;

  TransactionImpl(ContextInternal context, Handler endHandler, Connection connection) {
    this.context = context;
    this.connection = connection;
    this.completion = context.promise();
    this.endHandler = endHandler;
  }

  Future begin() {
    PromiseInternal promise = context.promise();
    TxCommand begin = new TxCommand<>(TxCommand.Kind.BEGIN, this);
    begin.handler = wrap(begin, promise);
    schedule(begin);
    return promise.future();
  }

  public void fail() {
    failed = true;
  }

  private  void execute(CommandBase cmd) {
    Handler> handler = cmd.handler;
    connection.schedule(context, cmd).onComplete(handler);
  }

  private  Handler> wrap(CommandBase cmd, Promise handler) {
    return ar -> {
      CommandBase abc = cmd;
      synchronized (TransactionImpl.this) {
        pendingQueries--;
      }
      checkEnd();
      handler.handle(ar);
    };
  }

  public  void schedule(CommandBase cmd, Promise handler) {
    cmd.handler = wrap(cmd, handler);
    if (!schedule(cmd)) {
      handler.fail("Transaction already completed");
    }
  }

  public  boolean schedule(CommandBase b) {
    synchronized (this) {
      if (ended) {
        return false;
      }
      pendingQueries++;
    }
    execute(b);
    return true;
  }

  private void checkEnd() {
    TxCommand cmd;
    synchronized (this) {
      if (pendingQueries > 0 || !ended || endCommand != null) {
        return;
      }
      TxCommand.Kind kind = failed ? TxCommand.Kind.ROLLBACK : TxCommand.Kind.COMMIT;
      endCommand = txCommand(kind);
      cmd = endCommand;
    }
    endHandler.handle(null);
    execute(cmd);
  }

  private Future end(boolean rollback) {
    synchronized (this) {
      if (endCommand != null) {
        return context.failedFuture("Transaction already complete");
      }
      ended = true;
      failed |= rollback;
    }
    checkEnd();
    return completion.future();
  }

  @Override
  public Future commit() {
    return end(false).flatMap(k -> {
      if (k == TxCommand.Kind.COMMIT) {
        return Future.succeededFuture();
      } else {
        return Future.failedFuture(TransactionRollbackException.INSTANCE);
      }
    });
  }

  public void commit(Handler> handler) {
    Future fut = commit();
    if (handler != null) {
      fut.onComplete(handler);
    }
  }

  @Override
  public Future rollback() {
    return end(true).mapEmpty();
  }

  public void rollback(Handler> handler) {
    Future fut = rollback();
    if (handler != null) {
      fut.onComplete(handler);
    }
  }

  private TxCommand txCommand(TxCommand.Kind kind) {
    TxCommand cmd = new TxCommand<>(kind, null);
    cmd.handler = ar -> {
      if (ar.succeeded()) {
        completion.complete(kind);
      } else {
        completion.fail(ar.cause());
      }
    };
    return cmd;
  }

  @Override
  public void completion(Handler> handler) {
    completion().onComplete(handler);
  }

  @Override
  public Future completion() {
    return completion.future().flatMap(k -> {
      if (k == TxCommand.Kind.COMMIT) {
        return Future.succeededFuture();
      } else {
        return Future.failedFuture(TransactionRollbackException.INSTANCE);
      }
    });
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy