@Override
  public void releaseExclusiveReadLock(
      GenericFileOperations<File> operations, GenericFile<File> file, Exchange exchange)
      throws Exception {

    // must call super
    super.releaseExclusiveReadLock(operations, file, exchange);

    String target = file.getFileName();
    FileLock lock = exchange.getProperty(Exchange.FILE_LOCK_EXCLUSIVE_LOCK, FileLock.class);
    RandomAccessFile rac =
        exchange.getProperty(Exchange.FILE_LOCK_RANDOM_ACCESS_FILE, RandomAccessFile.class);

    if (lock != null) {
      Channel channel = lock.acquiredBy();
      try {
        lock.release();
      } finally {
        // close channel as well
        IOHelper.close(channel, "while releasing exclusive read lock for file: " + target, LOG);
        IOHelper.close(rac, "while releasing exclusive read lock for file: " + target, LOG);
      }
    }
  }
  @Override
  public boolean acquireExclusiveReadLock(
      GenericFileOperations<File> operations, GenericFile<File> file, Exchange exchange)
      throws Exception {
    // must call super
    if (!super.acquireExclusiveReadLock(operations, file, exchange)) {
      return false;
    }

    File target = new File(file.getAbsoluteFilePath());

    LOG.trace("Waiting for exclusive read lock to file: {}", target);

    FileChannel channel = null;
    RandomAccessFile randomAccessFile = null;

    boolean exclusive = false;
    FileLock lock = null;

    try {
      randomAccessFile = new RandomAccessFile(target, "rw");
      // try to acquire rw lock on the file before we can consume it
      channel = randomAccessFile.getChannel();

      StopWatch watch = new StopWatch();

      while (!exclusive) {
        // timeout check
        if (timeout > 0) {
          long delta = watch.taken();
          if (delta > timeout) {
            CamelLogger.log(
                LOG,
                readLockLoggingLevel,
                "Cannot acquire read lock within "
                    + timeout
                    + " millis. Will skip the file: "
                    + target);
            // we could not get the lock within the timeout period, so return false
            return false;
          }
        }

        // get the lock using either try lock or not depending on if we are using timeout or not
        try {
          lock = timeout > 0 ? channel.tryLock() : channel.lock();
        } catch (IllegalStateException ex) {
          // Also catch the OverlappingFileLockException here. Do nothing here
        }
        if (lock != null) {
          LOG.trace("Acquired exclusive read lock: {} to file: {}", lock, target);
          exclusive = true;
        } else {
          boolean interrupted = sleep();
          if (interrupted) {
            // we were interrupted while sleeping, we are likely being shutdown so return false
            return false;
          }
        }
      }
    } catch (IOException e) {
      // must handle IOException as some apps on Windows etc. will still somehow hold a lock to a
      // file
      // such as AntiVirus or MS Office that has special locks for it's supported files
      if (timeout == 0) {
        // if not using timeout, then we cant retry, so return false
        return false;
      }
      LOG.debug("Cannot acquire read lock. Will try again.", e);
      boolean interrupted = sleep();
      if (interrupted) {
        // we were interrupted while sleeping, we are likely being shutdown so return false
        return false;
      }
    } finally {
      // close channels if we did not grab the lock
      if (!exclusive) {
        IOHelper.close(channel, "while acquiring exclusive read lock for file: " + target, LOG);
        IOHelper.close(
            randomAccessFile, "while acquiring exclusive read lock for file: " + target, LOG);

        // and also must release super lock
        super.releaseExclusiveReadLock(operations, file, exchange);
      }
    }

    // we grabbed the lock
    exchange.setProperty(Exchange.FILE_LOCK_EXCLUSIVE_LOCK, lock);
    exchange.setProperty(Exchange.FILE_LOCK_RANDOM_ACCESS_FILE, randomAccessFile);

    return true;
  }