Пример #1
0
  /** Open up what is done so clients can provide a context callback */
  public void execute(ContextCallback cc) throws NamingException {
    Context ctx = null;

    try {
      ctx = contextFactory.getContext();
      cc.doInContext(ctx);
    }
    // catch (NamingException ex) {
    //    throw new NamingException(("Couldn't bind JNDI object to name [" + name + "]", ex);
    // }
    finally {
      try {
        if (ctx != null) ctx.close();
      } catch (NamingException ex) {
        //
      }
    }
  } // execute
  private TransactionResult<T> doAppend(final TimeoutUnit timeoutUnit, final boolean block) {
    Logger.log(
        "ReentrantSynchronizationContext",
        "doAppend#timeoutUnit = "
            + timeoutUnit
            + ", block = "
            + block
            + ", done.get() = "
            + done.get());
    TransactionResult<T> retValue = null;

    // possible to proceed only if there were no shutdown call on this instance
    if (!done.get()) {

      // latch for calling thread
      CountDownLatch localBarrier;

      // if the calling thread is a first on in this iteration the flag will get 'true' value
      boolean needInitiateTransaction;

      // each iteration has it's own instance of threadLocalTransactionId. Also it holds the current
      // iteration transaction value.
      // null means default value should be used
      final AtomicReference<TransactionResult<T>> threadLocalTransactionId;

      // nobody can go through if the same monitor is taken in other place. Probably in finalization
      // routine
      Logger.log("ReentrantSynchronizationContext", "doAppend#before sync");
      synchronized (mutex) {
        Logger.log("ReentrantSynchronizationContext", "doAppend#after sync");
        // each calling thread would have it's own latch.
        // It's supposed that some other awaking activity would countdown all the latches from list.
        localBarrier = new CountDownLatch(1);

        // list of all latches and associated threads. Used to release all threads at once for this
        // transaction iteration
        awaitingThreads.add(localBarrier);
        // barierList.add(localBarrier);

        // see description above
        needInitiateTransaction = false;
        if (transactionInProgress.compareAndSet(false, true)) {
          // if we first time in this iteration in this peace of code we mark that new transaction
          // shoud be started
          needInitiateTransaction = true;
          // also we prepare new transaction id. null means we don't have outer call to release()
          transactionId.set(new AtomicReference<TransactionResult<T>>(null));
        }
        // each thread must hold transaction id it it's own heap
        threadLocalTransactionId = transactionId.get();
      }

      // call outer initialization routine
      if (needInitiateTransaction) {
        Logger.log("ReentrantSynchronizationContext", "initiateTransaction#start");
        callback.initiateTransaction();
        Logger.log("ReentrantSynchronizationContext", "initiateTransaction#end");
      }

      if (block) {
        TransactionResult.Reason reason = TransactionResult.Reason.OUTER_INTERRUPT;
        try {
          // make thread to wait until transaction finished or TIMEOUT EXPIRES
          if (timeoutUnit != null) {
            Logger.log(
                "ReentrantSynchronizationContext", "start await, timeoutUnit = " + timeoutUnit);
            localBarrier.await(
                timeoutUnit.getTimeout(),
                timeoutUnit.getTimeoutUnit() == null
                    ? TimeUnit.MILLISECONDS
                    : timeoutUnit.getTimeoutUnit());
          } else {
            localBarrier.await();
          }

          reason =
              localBarrier.getCount() > 0
                  ? TransactionResult.Reason.TIMEOUT
                  : TransactionResult.Reason.OUTER_INTERRUPT;

          Logger.log("ReentrantSynchronizationContext", "end await, reason = " + reason);
        } catch (InterruptedException e) {
          // set thread flag
          Thread.interrupted();
          reason = TransactionResult.Reason.OUTER_INTERRUPT;
        } finally {
          // try to run finalization routine
          final TransactionResult<T> transactionResult = threadLocalTransactionId.get();
          Logger.log("ReentrantSynchronizationContext", "start tr. finalization");
          runFinalization(
              threadLocalTransactionId,
              true,
              reason,
              transactionResult == null ? null : transactionResult.getValue(),
              callback);
          Logger.log("ReentrantSynchronizationContext", "end tr. finalization");
          retValue = threadLocalTransactionId.get();
          Logger.log(
              "ReentrantSynchronizationContext", "start tr. finalization, retValue = " + retValue);
        }
      } else {
        if (needInitiateTransaction) {
          boolean needTimeout =
              !(timeoutUnit == null
                  || timeoutUnit.getTimeout() == null
                  || timeoutUnit.getTimeoutUnit() == null);

          if (needTimeout) {
            long timeoutInMillis = timeoutUnit.getTimeoutUnit().toMillis(timeoutUnit.getTimeout());

            repetitiousTaskManager.startDelayedTask(
                threadLocalTransactionId,
                new RepetitiousTaskManager.Repeater<AtomicReference<TransactionResult<T>>>() {
                  @Override
                  public void onRepeat(
                      AtomicReference<TransactionResult<T>> key, Shutdownable shutdownable) {
                    Logger.log(TAG, String.format("onRepeat"));
                    final TransactionResult<T> transactionResult = key.get();
                    runFinalization(
                        key,
                        true,
                        TransactionResult.Reason.TIMEOUT,
                        transactionResult == null ? null : transactionResult.getValue(),
                        callback);
                    shutdownable.shutdown();
                  }
                },
                timeoutInMillis);
          }
        }
      }
    } else {
      throw new IllegalStateException("Context already shutdown.");
    }

    return retValue;
  }