/camel-core/src/main/java/org/apache/camel/component/file/strategy/FileLockExclusiveReadLockStrategy.java

https://github.com/jatin-28/camel · Java · 169 lines · 113 code · 21 blank · 35 comment · 13 complexity · 66044643f63414c4c0df529447bae12a MD5 · raw file

  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.camel.component.file.strategy;
  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.io.RandomAccessFile;
  21. import java.nio.channels.Channel;
  22. import java.nio.channels.FileChannel;
  23. import java.nio.channels.FileLock;
  24. import org.apache.camel.Exchange;
  25. import org.apache.camel.LoggingLevel;
  26. import org.apache.camel.component.file.GenericFile;
  27. import org.apache.camel.component.file.GenericFileEndpoint;
  28. import org.apache.camel.component.file.GenericFileOperations;
  29. import org.apache.camel.util.CamelLogger;
  30. import org.apache.camel.util.IOHelper;
  31. import org.apache.camel.util.StopWatch;
  32. import org.slf4j.Logger;
  33. import org.slf4j.LoggerFactory;
  34. /**
  35. * Acquires exclusive read lock to the given file. Will wait until the lock is granted.
  36. * After granting the read lock it is released, we just want to make sure that when we start
  37. * consuming the file its not currently in progress of being written by third party.
  38. */
  39. public class FileLockExclusiveReadLockStrategy extends MarkerFileExclusiveReadLockStrategy {
  40. private static final transient Logger LOG = LoggerFactory.getLogger(FileLockExclusiveReadLockStrategy.class);
  41. private long timeout;
  42. private long checkInterval = 1000;
  43. private FileLock lock;
  44. private String lockFileName;
  45. private LoggingLevel readLockLoggingLevel = LoggingLevel.WARN;
  46. @Override
  47. public void prepareOnStartup(GenericFileOperations<File> operations, GenericFileEndpoint<File> endpoint) {
  48. // noop
  49. }
  50. @Override
  51. public boolean acquireExclusiveReadLock(GenericFileOperations<File> operations, GenericFile<File> file, Exchange exchange) throws Exception {
  52. // must call super
  53. if (!super.acquireExclusiveReadLock(operations, file, exchange)) {
  54. return false;
  55. }
  56. File target = new File(file.getAbsoluteFilePath());
  57. LOG.trace("Waiting for exclusive read lock to file: {}", target);
  58. try {
  59. // try to acquire rw lock on the file before we can consume it
  60. FileChannel channel = new RandomAccessFile(target, "rw").getChannel();
  61. boolean exclusive = false;
  62. StopWatch watch = new StopWatch();
  63. while (!exclusive) {
  64. // timeout check
  65. if (timeout > 0) {
  66. long delta = watch.taken();
  67. if (delta > timeout) {
  68. CamelLogger.log(LOG, readLockLoggingLevel,
  69. "Cannot acquire read lock within " + timeout + " millis. Will skip the file: " + target);
  70. // we could not get the lock within the timeout period, so return false
  71. return false;
  72. }
  73. }
  74. // get the lock using either try lock or not depending on if we are using timeout or not
  75. try {
  76. lock = timeout > 0 ? channel.tryLock() : channel.lock();
  77. } catch (IllegalStateException ex) {
  78. // Also catch the OverlappingFileLockException here. Do nothing here
  79. }
  80. if (lock != null) {
  81. LOG.trace("Acquired exclusive read lock: {} to file: {}", lock, target);
  82. lockFileName = target.getName();
  83. exclusive = true;
  84. } else {
  85. boolean interrupted = sleep();
  86. if (interrupted) {
  87. // we were interrupted while sleeping, we are likely being shutdown so return false
  88. return false;
  89. }
  90. }
  91. }
  92. } catch (IOException e) {
  93. // must handle IOException as some apps on Windows etc. will still somehow hold a lock to a file
  94. // such as AntiVirus or MS Office that has special locks for it's supported files
  95. if (timeout == 0) {
  96. // if not using timeout, then we cant retry, so rethrow
  97. throw e;
  98. }
  99. LOG.debug("Cannot acquire read lock. Will try again.", e);
  100. boolean interrupted = sleep();
  101. if (interrupted) {
  102. // we were interrupted while sleeping, we are likely being shutdown so return false
  103. return false;
  104. }
  105. }
  106. return true;
  107. }
  108. @Override
  109. public void releaseExclusiveReadLock(GenericFileOperations<File> operations,
  110. GenericFile<File> file, Exchange exchange) throws Exception {
  111. // must call super
  112. super.releaseExclusiveReadLock(operations, file, exchange);
  113. if (lock != null) {
  114. Channel channel = lock.channel();
  115. try {
  116. lock.release();
  117. } finally {
  118. // must close channel first
  119. IOHelper.close(channel, "while acquiring exclusive read lock for file: " + lockFileName, LOG);
  120. }
  121. }
  122. }
  123. private boolean sleep() {
  124. LOG.trace("Exclusive read lock not granted. Sleeping for {} millis.", checkInterval);
  125. try {
  126. Thread.sleep(checkInterval);
  127. return false;
  128. } catch (InterruptedException e) {
  129. LOG.debug("Sleep interrupted while waiting for exclusive read lock, so breaking out");
  130. return true;
  131. }
  132. }
  133. public long getTimeout() {
  134. return timeout;
  135. }
  136. @Override
  137. public void setTimeout(long timeout) {
  138. this.timeout = timeout;
  139. }
  140. @Override
  141. public void setCheckInterval(long checkInterval) {
  142. this.checkInterval = checkInterval;
  143. }
  144. @Override
  145. public void setReadLockLoggingLevel(LoggingLevel readLockLoggingLevel) {
  146. this.readLockLoggingLevel = readLockLoggingLevel;
  147. }
  148. }