/**
   * Tests start and end with regard to locking. Going to cut down the timeout to a very short
   * period, the lock should expire
   *
   * @throws Exception
   */
  public void testLockTimeout() throws Exception {

    RetryingTransactionHelper trx = transactionService.getRetryingTransactionHelper();

    /** Simulates a client starting a transfer and then "going away"; */
    RetryingTransactionCallback<Object> startWithoutAnythingElse =
        new RetryingTransactionCallback<Object>() {

          public Object execute() throws Throwable {

            ftTransferReceiver.start("1234", true, ftTransferReceiver.getVersion());
            return null;
          }
        };

    RetryingTransactionCallback<Object> slowTransfer =
        new RetryingTransactionCallback<Object>() {

          public Object execute() throws Throwable {

            String transferId =
                ftTransferReceiver.start("1234", true, ftTransferReceiver.getVersion());
            Thread.sleep(1000);
            try {
              ftTransferReceiver.saveSnapshot(transferId, null);
              fail("did not timeout");
            } catch (TransferException te) {
              // expect to go here with a timeout
            }
            return null;
          }
        };

    long lockRefreshTime = ftTransferReceiver.getLockRefreshTime();
    long lockTimeOut = ftTransferReceiver.getLockTimeOut();

    try {
      ftTransferReceiver.setLockRefreshTime(500);
      ftTransferReceiver.setLockTimeOut(200);

      /**
       * This test simulates a client that starts a transfer and then "goes away". We kludge the
       * timeouts to far shorter than normal to make the test run in a reasonable time.
       */
      for (int i = 0; i < 3; i++) {
        trx.doInTransaction(startWithoutAnythingElse, false, true);
        Thread.sleep(1000);
      }
      trx.doInTransaction(slowTransfer, false, true);
    } finally {
      ftTransferReceiver.setLockRefreshTime(lockRefreshTime);
      ftTransferReceiver.setLockTimeOut(lockTimeOut);
    }
  }
  /** @param p The person context to set. */
  public void setPerson(final Node p) {
    // perform the set in a txn as certain bean calls require it
    FacesContext context = FacesContext.getCurrentInstance();
    RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(context);
    RetryingTransactionCallback callback =
        new RetryingTransactionCallback() {
          public Object execute() throws Throwable {
            person = p;
            userName = (String) person.getProperties().get(ContentModel.PROP_USERNAME);

            // rebuild the property immutability map helper object
            immutabilty =
                new PropertyImmutabilityMap(
                    getUserRegistrySynchronizer().getPersonMappedProperties(userName));

            return null;
          }
        };
    try {
      txnHelper.doInTransaction(callback, false);
    } catch (Throwable e) {
      // reset the flag so we can re-attempt the operation
      if (e instanceof ReportedException == false) {
        Utils.addErrorMessage(e.getMessage(), e);
      }
      ReportedException.throwIfNecessary(e);
    }
  }
 /** Get the tags from the IKS engine and tag the node */
 public void run() {
   RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
   RetryingTransactionCallback<Collection<String>> callback =
       new RetryingTransactionCallback<Collection<String>>() {
         public Collection<String> execute() throws Throwable {
           try {
             behaviourFilter.disableBehaviour(ContentModel.TYPE_CONTENT);
             Collection<String> tags = iksFiseAlfrescoBl.extractAndEnrichContent(nodeRef);
             if (logger.isDebugEnabled()) {
               logger.debug("New tags for node " + nodeRef + ": " + tags);
             }
             return tags;
           } finally {
             behaviourFilter.enableBehaviour(ContentModel.TYPE_CONTENT);
           }
         }
       };
   try {
     txnHelper.doInTransaction(callback, false, true);
   } catch (InvalidNodeRefException e) {
     if (logger.isDebugEnabled()) {
       logger.error("Unable to update tags on missing node: " + nodeRef);
     }
   } catch (Throwable e) {
     logger.error(e.getLocalizedMessage(), e);
   }
 }
  private static void deleteUser(final String userName) {
    TRANSACTION_HELPER.doInTransaction(
        new RetryingTransactionHelper.RetryingTransactionCallback<Void>() {
          @Override
          public Void execute() throws Throwable {
            if (PERSON_SERVICE.personExists(userName)) {
              PERSON_SERVICE.deletePerson(userName);
            }

            return null;
          }
        });
  }
 public static Object withTx(
     final Context context, final Scriptable thisObj, final Object[] args, Function funObj) {
   if (args[0] instanceof Function) {
     final Function closure = (Function) args[0];
     RetryingTransactionHelper txnHelper =
         getInstance().serviceRegistry.getTransactionService().getRetryingTransactionHelper();
     return txnHelper.doInTransaction(
         new RetryingTransactionCallback() {
           @Override
           public Object execute() throws Throwable {
             logger.debug("Calling function within tx");
             return closure.call(context, null, thisObj, new Object[] {});
           }
         });
   }
   return null;
 }
  /**
   * Deletes the specified NodeRefs, if they exist.
   *
   * @param nodesToDelete
   */
  private static void performDeletionOfNodes(final List<NodeRef> nodesToDelete) {
    TRANSACTION_HELPER.doInTransaction(
        new RetryingTransactionHelper.RetryingTransactionCallback<Void>() {
          @Override
          public Void execute() throws Throwable {
            AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER);

            for (NodeRef node : nodesToDelete) {
              if (NODE_SERVICE.exists(node)) {
                NODE_SERVICE.deleteNode(node);
              }
            }

            return null;
          }
        });
  }
  private static void createUser(final String userName) {
    TRANSACTION_HELPER.doInTransaction(
        new RetryingTransactionHelper.RetryingTransactionCallback<Void>() {
          @Override
          public Void execute() throws Throwable {
            if (!AUTHENTICATION_SERVICE.authenticationExists(userName)) {
              AUTHENTICATION_SERVICE.createAuthentication(userName, "PWD".toCharArray());
            }

            if (!PERSON_SERVICE.personExists(userName)) {
              PropertyMap ppOne = new PropertyMap();
              ppOne.put(ContentModel.PROP_USERNAME, userName);
              ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
              ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
              ppOne.put(ContentModel.PROP_EMAIL, "*****@*****.**");
              ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");

              PERSON_SERVICE.createPerson(ppOne);
            }

            return null;
          }
        });
  }
  /**
   * Tests start and end with regard to locking.
   *
   * @throws Exception
   */
  public void testStartAndEnd() throws Exception {

    RetryingTransactionHelper trx = transactionService.getRetryingTransactionHelper();

    RetryingTransactionCallback<Object> cb =
        new RetryingTransactionCallback<Object>() {

          public Object execute() throws Throwable {

            String transferId =
                ftTransferReceiver.start("1234", true, ftTransferReceiver.getVersion());
            File stagingFolder = null;
            try {

              stagingFolder = ftTransferReceiver.getStagingFolder(transferId);
              assertTrue(ftTransferReceiver.getStagingFolder(transferId).exists());
              NodeRef tempFolder = ftTransferReceiver.getTempFolder(transferId);
              assertNotNull("tempFolder is null", tempFolder);

              Thread.sleep(1000);
              try {
                ftTransferReceiver.start("1234", true, ftTransferReceiver.getVersion());
                fail("Successfully started twice!");
              } catch (TransferException ex) {
                // Expected
              }

              Thread.sleep(300);
              try {
                ftTransferReceiver.start("1234", true, ftTransferReceiver.getVersion());
                fail("Successfully started twice!");
              } catch (TransferException ex) {
                // Expected
              }

              try {
                ftTransferReceiver.end(
                    new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, GUID.generate())
                        .toString());
                // FIXME: This test is failing
                //                            fail("Successfully ended with transfer id that doesn't
                // own lock.");
              } catch (TransferException ex) {
                // Expected
              }
            } finally {

              ftTransferReceiver.end(transferId);

              /** Check clean-up */
              if (stagingFolder != null) {
                assertFalse(stagingFolder.exists());
              }
            }

            return null;
          }
        };

    long oldRefreshTime = ftTransferReceiver.getLockRefreshTime();
    try {
      ftTransferReceiver.setLockRefreshTime(500);

      for (int i = 0; i < 5; i++) {

        trx.doInTransaction(cb, false, true);
      }
    } finally {
      ftTransferReceiver.setLockRefreshTime(oldRefreshTime);
    }
  }
  /** {@inheritDoc} */
  @Override
  protected void executeJob(final Job jobIn) {
    if ((!isActive) || (alfrescoJobExecutor.getTransactionService().isReadOnly())) {
      return;
    }

    // based on JBPM 3.3.1 (JobExecutorThread.executeJob)
    // - wrap executeJob / deleteJob in Alfresco retries
    // - add setRollbackOnly warnings
    // - if Alfresco retries fail, attempt to set JBPM job exception/retries

    try {
      RetryingTransactionHelper tranHelper =
          alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper();
      tranHelper.doInTransaction(
          new RetryingTransactionCallback<Object>() {
            public Object execute() throws Throwable {
              JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
              try {
                JobSession jobSession = jbpmContext.getJobSession();
                Job job = jobSession.loadJob(jobIn.getId());

                if (logger.isTraceEnabled()) {
                  logger.trace("executing " + job);
                }

                if (job.execute(jbpmContext)) {
                  jobSession.deleteJob(job);

                  if (logger.isDebugEnabled()) {
                    logger.debug("executed and deleted: " + job);
                  }
                }

                // if this job is locked too long
                long totalLockTimeInMillis =
                    System.currentTimeMillis() - job.getLockTime().getTime();
                if (totalLockTimeInMillis > jbpmMaxLockTime) {
                  logger.warn(
                      "setRollbackOnly: exceeded maxLockTime (" + jbpmMaxLockTime + ") " + job);
                  jbpmContext.setRollbackOnly();
                }
              } finally {
                jbpmContext.close();
              }

              return null;
            }
          });
    } catch (LockAcquisitionException e) {
      // ignore
      jobLockToken = null;
    } catch (Exception e) {
      if (logger.isErrorEnabled()) {
        logger.error("failed to execute " + jobIn, e);
      }

      if (!isPersistenceException(e)) {
        try {
          final StringWriter memoryWriter = new StringWriter();
          e.printStackTrace(new PrintWriter(memoryWriter));

          RetryingTransactionHelper tranHelper =
              alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper();
          tranHelper.doInTransaction(
              new RetryingTransactionCallback<Object>() {
                public Object execute() throws Throwable {
                  JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
                  try {
                    JobSession jobSession = jbpmContext.getJobSession();
                    final Job job = jobSession.loadJob(jobIn.getId());

                    if (logger.isDebugEnabled()) {
                      logger.debug("attempting to update exception/retries: " + job);
                    }

                    job.setException(memoryWriter.toString());
                    job.setRetries(job.getRetries() - 1);

                    if (logger.isInfoEnabled()) {
                      logger.info(
                          "updated job exception and set to "
                              + job.getRetries()
                              + " retries: "
                              + jobIn);
                    }
                  } finally {
                    jbpmContext.close();
                  }

                  return null;
                }
              });
        } catch (Exception e2) {
          if (logger.isErrorEnabled()) {
            logger.error("failed to update job exception/retries " + jobIn, e2);
          }
        }
      }
    }
  }